Compare commits

...

No commits in common. "master" and "gh-pages" have entirely different histories.

92 changed files with 9075 additions and 4227 deletions

View file

@ -1,14 +0,0 @@
# editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false

13
.github/FUNDING.yml vendored
View file

@ -1,13 +0,0 @@
# These are supported funding model platforms
github: jeffreytse # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: jeffreytse
open_collective: # Replace with a single Open Collective username
ko_fi: jeffreytse
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: jeffreytse
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View file

@ -1,33 +0,0 @@
name: Github Pages
on:
push:
branches:
- master # Here source code branch is `master`, it could be other branch
jobs:
build_and_deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
# Use GitHub Actions' cache to cache dependencies on servers
- uses: actions/cache@v1
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-gems-
# Use GitHub Deploy Action to build and deploy to Github
- uses: jeffreytse/jekyll-deploy-action@master
with:
provider: 'github'
token: ${{ secrets.GITHUB_TOKEN }} # It's your Personal Access Token(PAT)
repository: '' # Default is current repository
branch: 'gh-pages' # Default is gh-pages for github provider
jekyll_src: './' # Default is root directory
jekyll_cfg: '_config.yml' # Default is _config.yml
jekyll_baseurl: '' # Default is empty
cname: 'caras.cafe' # Default is to not use a cname
actor: '' # Default is the GITHUB_ACTOR

5
.gitignore vendored
View file

@ -1,5 +0,0 @@
*.gem
.bundle
.sass-cache
_site
Gemfile.lock

0
.nojekyll Normal file
View file

662
404.html
View file

@ -1,3 +1,659 @@
---
layout: 404
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="google-translate-customization" content="108d9124921d80c3-80e20d618ff053c8-g4f02ec6f3dba68b7-c">
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>Matyáš Caras | Welcome to my website/blog, full of weird stuff written by yours truly.</title>
<meta name="generator" content="Jekyll v4.3.1">
<meta property="og:title" content="Matyáš Caras">
<meta name="author" content="hernikplays">
<meta property="og:locale" content="en_US">
<meta name="description" content="Welcome to my website/blog, full of weird stuff written by yours truly.">
<meta property="og:description" content="Welcome to my website/blog, full of weird stuff written by yours truly.">
<link rel="canonical" href="https://caras.cafe/404.html">
<meta property="og:url" content="https://caras.cafe/404.html">
<meta property="og:site_name" content="Matyáš Caras">
<meta property="og:type" content="website">
<meta name="twitter:card" content="summary">
<meta property="twitter:title" content="Matyáš Caras">
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"WebPage","author":{"@type":"Person","name":"hernikplays"},"description":"Welcome to my website/blog, full of weird stuff written by yours truly.","headline":"Matyáš Caras","url":"https://caras.cafe/404.html"}</script>
<!-- End Jekyll SEO tag -->
<link rel="shortcut icon" href="">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/typeface-noto-sans@0.0.72/index.min.css">
<link rel="stylesheet" href="/assets/css/main.css">
<script src="/assets/js/main.js"></script><link type="application/atom+xml" rel="alternate" href="https://caras.cafe/feed.xml" title="Matyáš Caras">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js"></script>
<!-- and it's easy to individually load additional languages -->
<script charset="UTF-8" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/languages/go.min.js"></script>
<script>
// Init highlight js
document.addEventListener('DOMContentLoaded', function(event) {
var els = document.querySelectorAll('pre code')
function addLangData(block) {
var outer = block.parentElement.parentElement.parentElement;
var lang = block.getAttribute('data-lang');
for (var i = 0; i < outer.classList.length; i++) {
var cls = outer.classList[i];
if (cls.startsWith('language-')) {
lang = cls;
break;
}
}
if (!lang) {
cls = block.getAttribute('class');
lang = cls ? cls.replace('hljs ', '') : '';
}
if (lang.startsWith('language-')) {
lang = lang.substr(9);
}
block.setAttribute('class', 'hljs ' + lang);
block.parentNode.setAttribute('data-lang', lang);
}
function addBadge(block) {
var enabled = ('true' || 'true').toLowerCase();
if (enabled == 'true') {
var pre = block.parentElement;
pre.classList.add('badge');
}
}
function handle(block) {
addLangData(block);
addBadge(block)
hljs.highlightBlock(block);
}
for (var i = 0; i < els.length; i++) {
var el = els[i];
handle(el);
}
});
</script>
<style>
/* code language badge */
pre.badge::before {
content: attr(data-lang);
color: #fff;
background-color: #ff4e00;
padding: 0 .5em;
border-radius: 0 2px;
text-transform: uppercase;
text-align: center;
min-width: 32px;
display: inline-block;
position: absolute;
right: 0;
}
/* fix wrong badge display for firefox browser */
code > table pre::before {
display: none;
}
</style>
</head>
<body>
<header class="site-header " role="banner">
<div class="wrapper">
<div class="site-header-inner">
<span class="site-brand"><a class="site-brand-inner" rel="author" href="/">
<img class="site-favicon" title="Matyáš Caras" src="" onerror="this.style.display='none'">
Matyáš Caras
</a>
</span><nav class="site-nav">
<input type="checkbox" id="nav-trigger" class="nav-trigger">
<label for="nav-trigger">
<span class="menu-icon">
<svg viewbox="0 0 18 15" width="18px" height="15px">
<path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"></path>
</svg>
</span>
</label>
<div class="trigger">
<a class="page-link" href="/about.html">ABOUT</a><a class="page-link" href="/archives.html">ARCHIVES</a><a class="page-link" href="/categories.html">CATEGORIES</a><a class="page-link" href="/">HOME</a><a class="page-link" href="/tags.html">TAGS</a>
</div>
</nav>
</div>
</div>
</header>
<script>
function initHeader() {
var lastScrollY = getScrollPos().y;
var documentElement = document.documentElement;
function storeScrollData() {
var y = getScrollPos().y;var scrollStatus = "";
if (y <= 0) {
scrollStatus = "top";
} else if ((window.innerHeight + y) >= document.body.offsetHeight) {
scrollStatus = "bottom";
} else {
var isScrollDown = (y - lastScrollY > 0) ? true : false;
scrollStatus = isScrollDown ? "down" : "up";
}
lastScrollY = y;
documentElement.setAttribute("data-scroll-status", scrollStatus);
}
window.addEventListener('scroll', function(e) {
storeScrollData();
});
storeScrollData();
}
document.addEventListener('DOMContentLoaded', initHeader);
</script>
<script>
function hashLocate(hashValue) {
hashValue = hashValue.replace(/^.*#h-/, '');
hashValue = decodeURIComponent(hashValue);
var element = document.getElementById(hashValue);
if (!element) {
return;
}
var header = document.querySelector('header.site-header');
var headerRect = header.getBoundingClientRect();
var headerTop = Math.floor(headerRect.top);
var headerHeight = Math.floor(headerRect.height);
var scrollPos = getScrollPos();
var offsetY = element.offsetTop - (headerTop + headerHeight + 20);
if (offsetY == scrollPos.y) {
return;
}
if (headerTop == 0 && offsetY > scrollPos.y) {
offsetY += headerHeight + 2;
} else if (headerTop < 0 && offsetY < scrollPos.y) {
offsetY -= headerHeight - 2;
}
smoothScrollTo(offsetY);
}
// The first event occurred
window.addEventListener('load', function(event) {
if (window.location.hash) {
hashLocate(window.location.hash);
}
});
// The first event occurred
window.addEventListener('click', function(event) {
if (event.target.tagName.toLowerCase() == 'a') {
hashLocate(event.target.getAttribute('href'));
}
});
</script>
<div class="theme-toggle">
<input type="checkbox" id="theme-switch">
<label for="theme-switch">
<div class="toggle"></div>
<div class="names">
<p class="light">Light</p>
<p class="dark">Dark</p>
</div>
</label>
</div>
<script>
(function() {
var sw = document.getElementById('theme-switch');
var html = document.getElementsByTagName('html')[0];
var nightModeOption = ('auto' || 'auto').toLowerCase();
var storage = nightModeOption === 'manual'
? localStorage
: sessionStorage;
var themeData = loadThemeData();
function saveThemeData(data) {
storage.setItem('theme', JSON.stringify(data));
}
function loadThemeData() {
var data = storage.getItem('theme');
try {
data = JSON.parse(data ? data : '');
} catch(e) {
data = { nightShift: undefined, autoToggleAt: 0 };
saveThemeData(data);
}
return data;
}
function handleThemeToggle(nightShift) {
themeData.nightShift = nightShift;
saveThemeData(themeData);
html.dataset.theme = nightShift ? 'dark' : 'light';
setTimeout(function() {
sw.checked = nightShift ? true : false;
}, 50);
}
function autoThemeToggle() {
// Next time point of theme toggle
var now = new Date();
var toggleAt = new Date();
var hours = now.getHours();
var nightShift = hours >= 19 || hours <=7;
if (nightShift) {
if (hours > 7) {
toggleAt.setDate(toggleAt.getDate() + 1);
}
toggleAt.setHours(7);
} else {
toggleAt.setHours(19);
}
toggleAt.setMinutes(0);
toggleAt.setSeconds(0);
toggleAt.setMilliseconds(0)
var delay = toggleAt.getTime() - now.getTime();
// auto toggle theme mode
setTimeout(function() {
handleThemeToggle(!nightShift);
}, delay);
return {
nightShift: nightShift,
toggleAt: toggleAt.getTime()
};
}
// Listen the theme toggle event
sw.addEventListener('change', function(event) {
handleThemeToggle(event.target.checked);
});
if (nightModeOption == 'auto') {
var data = autoThemeToggle();
// Toggle theme by local setting
if (data.toggleAt > themeData.autoToggleAt) {
themeData.autoToggleAt = data.toggleAt;
handleThemeToggle(data.nightShift);
} else {
handleThemeToggle(themeData.nightShift);
}
} else if (nightModeOption == 'manual') {
handleThemeToggle(themeData.nightShift);
} else {
var nightShift = themeData.nightShift;
if (nightShift === undefined) {
nightShift = nightModeOption === 'on';
}
handleThemeToggle(nightShift);
}
})();
</script>
<div id="click-to-top" class="click-to-top">
<i class="fa fa-arrow-up"></i>
</div>
<script>
(function () {
const clickToTop = document.getElementById('click-to-top');
window.addEventListener('scroll', () => {
if (window.scrollY > 100) {
clickToTop.classList.add('show')
}else {
clickToTop.classList.remove('show')
}
});
clickToTop.addEventListener('click', () => {
window.smoothScrollTo(0);
});
})();
</script>
<main class="page-content" aria-label="Content">
<div class="wrapper">
<style type="text/css" media="screen">
.container {
margin: 10px auto;
max-width: 600px;
text-align: center;
}
h1 {
margin: 30px 0;
font-size: 4em;
line-height: 1;
letter-spacing: -1px;
}
</style>
<div class="container">
<h1>404</h1>
<p><strong>Page not found :(</strong></p>
<p>Try to check other pages through the menu. </p>
</div>
</div>
</main><footer class="site-footer h-card">
<data class="u-url" href="/"></data>
<div class="wrapper">
<div class="site-footer-inner">
<div>Copyright © 2021-2022 hernikplays</div>
<div>Powered by <a title="Jekyll is a simple, blog-aware, static site
generator." href="https://jekyllrb.com/">Jekyll</a> &amp; <a title="Yat, yet
another theme." href="https://github.com/jeffreytse/jekyll-theme-yat">Yat Theme</a>.</div>
<div><a rel="me" href="https://social.linux.pizza/@hernik">Mastodon</a></div>
<div class="footer-col rss-subscribe">Subscribe <a href="/feed.xml">via RSS</a>
</div>
</div>
</div>
</footer>
</body>
</html>

1
CNAME Normal file
View file

@ -0,0 +1 @@
caras.cafe

View file

@ -1,5 +0,0 @@
# frozen_string_literal: true
source "https://rubygems.org"
gemspec

View file

@ -1,217 +0,0 @@
# Welcome to Jekyll!
#
# About Theme
#
# Yet another theme for elegant writers with modern flat style and beautiful
# night/dark mode.
#
# Website: https://github.com/jeffreytse/jekyll-theme-yat
#
# You can do anything you want, including projects for your clients, as long
# as you mention an attribution back (credit links in footer or project).
# See the LICENCE file.
#
# This config file is meant for settings that affect your whole blog, values
# which you are expected to set up once and rarely edit after that.
#
# For technical reasons, this file is *NOT* reloaded automatically when you
# use 'bundle exec jekyll serve'. If you change this file, please restart
# the server process.
#
# Site settings
# These are used to personalize your new site. If you look in the HTML files,
# you will see them accessed via {{ site.title }}, {{ site.email }}, and so on.
# You can create any custom variable you would like, and they will be accessible
# in the templates via {{ site.myvariable }}.
title: Matyáš Caras
email: matyas@caras.cafe
author: hernikplays
# Copyright setting
# You can use any html code, currently below placeholders are available:
# * current year: {currentYear}
# * author: {author} (Value is the same as site.author)
# * copyright: (c) - ©
# * copyleft: (cleft)
# * sound recording copyright: (p) - ℗
#
# For example:
# "Copyright (c) 2017-{currentYear} <a href="https://example.com">{author}</a>"
# "Copyright © 2017-2021 Foobar"
#
copyright: 'Copyright (c) 2021-{currentYear} {author}, obsah dostupný pod licencí <a href="http://creativecommons.org/licenses/by-sa/4.0/" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC BY-SA 4.0<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/sa.svg"></a>'
description: >- # this means to ignore newlines until "baseurl:"
Mít blog je dnes trendy
baseurl: "" # the subpath of your site, e.g. /blog
url: "https://blog.caras.cafe" # the base hostname & protocol for your site, e.g. https://example.com
favicon: "" # the favicon for your site
# Yat date format
# refer to https://shopify.github.io/liquid/filters/date/ if you want to customize this
yat:
date_format: "%b %d, %Y"
# If you want more debug log, you can set true
# debug: false
# If you don't want transparent header, you can set false
# header_transparent: true
# If you want to change the content width, you can set to another value
# content_width: "920px"
# Google analytics
# google_analytics: [Tracking ID]
# If you want to generate website sitemap, you can set true
# sitemap: false
# If you want to change site language, you can set lang option
# lang: "en" # default lang is en
# Translate languges
# langs refer to https://cloud.google.com/translate/docs/languages
# translate_langs:
# - lang: en
# img: https://cdn.countryflags.com/thumbs/united-states-of-america/flag-400.png
# text: English
#
# - lang: fr
# img: https://cdn.countryflags.com/thumbs/france/flag-400.png
# text: French
#
# - lang: zh-CN
# img: https://cdn.countryflags.com/thumbs/china/flag-400.png
# text: Chinese(Simple)
#
# - lang: ja
# img: https://cdn.countryflags.com/thumbs/japan/flag-400.png
# text: Japanese
#
# - lang: ko
# img: https://cdn.countryflags.com/thumbs/south-korea/flag-400.png
# text: Korean
#
# - lang: ru
# img: https://cdn.countryflags.com/thumbs/russia/flag-400.png
# text: Russian
# You can choose a theme color
# Default theme colors as below:
# coolblack: #090a0b
# spacegrey: #353535
# snowwhite: #ffffff
#
# theme_color: snowwhite
#
# Custom color as below:
# theme_color: "#882250"
# You can choose a brand color
# Default brand colors as below:
# orangered: #ff5100
# greatgold: #f2cb05
# greenblue: #389092
#
# brand_color: orangered
#
# Custom color as below:
# brand_color: "#1a8e42"
# Night/Dark mode
# Default mode is "auto", "auto" is for auto nightshift
# (19:00 - 07:00), "manual" is for manual toggle, and
# "on/off" is for default on/off.
#
# Whatever the user's choice is, it will supersede the
# default setting of the site and be kept during the
# visit (session). Only the dark mode setting is"manual",
# it will be always kept on every visit (i.e. no matter
# the browser is closed or not)
#
# night_mode: "auto"
# Code badge setting
# You can enable or disable the code badge and so on
# code_badge:
# enabled: "true"
# color: "#fff"
# background_color: "#ff4e00"
# text_transform: "uppercase" # ("uppercase", "lowercase", "capitalize")
# If you want to link only specific pages in your header, uncomment
# this and add the path to the pages in order as they should show up
# header_pages:
# - index.html
# - archives.html
# - categories.html
# - tags.html
# - about.md
# Page default value
# defaults:
# home:
# heading: "Your awesome heading"
# subheading: "Your awesome subheading"
# banner: "Your image url"
# Banner default settings
# These banner settings are for global banner default, but you can also
# config it by the front matter for one specific post
# banner:
# video: null # Video banner source
# loop: true # Video loop
# volume: 0 # Video volume (100% is 1.0)
# start_at: 0 # Video start time
# image: null # Image banner source
# opacity: 1.0 # Banner opacity (100% is 1.0)
# background: "rgba(0, 0, 0, 0.8)" # Banner background (Could be a image)
# height: "640px" # Banner default height
# min_height: null # Banner minimum height
# heading_style: null # Custom heading style (e.g. "font-weight: bold; text-decoration: underline")
# subheading_style: null # Custom subheading style (e.g. color: gold)
# Excerpt size setting
# excerpt_size: 350
# Pagination setting
# paginate: 5
# Disqus comments
# disqus:
# shortname: "Your Disqus username"
# Gitment comments
# gitment:
# username: "Your GitHub username"
# repo: "The repo to store comments"
# client_id: "Your client ID"
# client_secret: "Your client secret"
# redirect_uri: "Your redirect url" # If you use a custom domain name
# Utterances comments
# See https://utteranc.es/
# set follow_site_theme true to make utterances' theme follow the site's
# utterances:
# repo: "owner/repo"
# issue_term: "title"
# label: "utterances comment"
# theme: "github-light"
# follow_site_theme: true
# Build settings
# highlighter: none
markdown: kramdown
kmarkdown:
input: GFM
plugins:
- jekyll-feed
- jekyll-seo-tag
- jekyll-sitemap
- jekyll-paginate
- jekyll-spaceship

View file

@ -1,3 +0,0 @@
home:
heading: "Hernikův Blog"
subheading: "Kecy a bláboly"

View file

@ -1,6 +0,0 @@
{% comment %}
Placeholder to allow defining custom head, in principle, you can add anything here, e.g. favicons:
1. Head over to https://realfavicongenerator.net/ to add your own favicons.
2. Customize default _includes/custom-head.html in your source directory and insert the given code snippet.
{% endcomment %}

View file

@ -1,18 +0,0 @@
<div id="click-to-top" class="click-to-top">
<i class="fa fa-arrow-up"></i>
</div>
<script>
(function () {
const clickToTop = document.getElementById('click-to-top');
window.addEventListener('scroll', () => {
if (window.scrollY > 100) {
clickToTop.classList.add('show')
}else {
clickToTop.classList.remove('show')
}
});
clickToTop.addEventListener('click', () => {
window.smoothScrollTo(0);
});
})();
</script>

View file

@ -1,91 +0,0 @@
<link rel="stylesheet"
href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js"></script>
<!-- and it's easy to individually load additional languages -->
<script charset="UTF-8"
src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/languages/go.min.js"></script>
{%- assign name = 'code_badge.enabled' -%}
{%- include functions.html func='get_value' default='true' -%}
{%- assign badge_enabled = return -%}
{%- assign name = 'code_badge.color' -%}
{%- include functions.html func='get_value' default='#fff' -%}
{%- assign badge_color = return -%}
{%- assign name = 'code_badge.background_color' -%}
{%- include functions.html func='get_value' default='#ff4e00' -%}
{%- assign badge_background_color = return -%}
{%- assign name = 'code_badge.text_transform' -%}
{%- include functions.html func='get_value' default='uppercase' -%}
{%- assign badge_text_transform = return -%}
<script>
// Init highlight js
document.addEventListener('DOMContentLoaded', function(event) {
var els = document.querySelectorAll('pre code')
function addLangData(block) {
var outer = block.parentElement.parentElement.parentElement;
var lang = block.getAttribute('data-lang');
for (var i = 0; i < outer.classList.length; i++) {
var cls = outer.classList[i];
if (cls.startsWith('language-')) {
lang = cls;
break;
}
}
if (!lang) {
cls = block.getAttribute('class');
lang = cls ? cls.replace('hljs ', '') : '';
}
if (lang.startsWith('language-')) {
lang = lang.substr(9);
}
block.setAttribute('class', 'hljs ' + lang);
block.parentNode.setAttribute('data-lang', lang);
}
function addBadge(block) {
var enabled = ('{{ badge_enabled }}' || 'true').toLowerCase();
if (enabled == 'true') {
var pre = block.parentElement;
pre.classList.add('badge');
}
}
function handle(block) {
addLangData(block);
addBadge(block)
hljs.highlightBlock(block);
}
for (var i = 0; i < els.length; i++) {
var el = els[i];
handle(el);
}
});
</script>
<style>
/* code language badge */
pre.badge::before {
content: attr(data-lang);
color: {{badge_color}};
background-color: {{badge_background_color}};
padding: 0 .5em;
border-radius: 0 2px;
text-transform: {{badge_text_transform}};
text-align: center;
min-width: 32px;
display: inline-block;
position: absolute;
right: 0;
}
/* fix wrong badge display for firefox browser */
code > table pre::before {
display: none;
}
</style>

View file

@ -1,17 +0,0 @@
<div id="disqus_thread"></div>
<script>
var disqus_config = function () {
this.page.url = '{{ page.url | absolute_url }}';
this.page.identifier = '{{ page.url | absolute_url }}';
};
(function() {
var d = document, s = d.createElement('script');
s.src = 'https://{{ site.disqus.shortname }}.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>

View file

@ -1,19 +0,0 @@
<div id="gitment_thread" class="giscus"></div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/theme-next/theme-next-gitment@1/default.css"/>
<script src="https://cdn.jsdelivr.net/gh/theme-next/theme-next-gitment@1/gitment.browser.js"></script>
<script src="https://giscus.app/client.js"
data-repo="hernikplays/blog"
data-repo-id="R_kgDOHr2B6w"
data-category="General"
data-category-id="DIC_kwDOHr2B684CSIhA"
data-mapping="pathname"
data-strict="0"
data-reactions-enabled="1"
data-emit-metadata="0"
data-input-position="top"
data-theme="transparent_dark"
data-lang="en"
data-loading="lazy"
crossorigin="anonymous"
async>
</script>

View file

@ -1,51 +0,0 @@
{%- if site.utterances.follow_site_theme -%}
<div id="utterances-placeholder"></div>
<script>
const utterancesThemeFromDataTheme = () => {
const dataTheme = document.documentElement.getAttribute('data-theme');
return `github-${dataTheme}`;
};
const setUtterancesTheme = () => {
const iframe = document.querySelector('.utterances-frame');
if (iframe) {
const message = {
type: 'set-theme',
theme: utterancesThemeFromDataTheme()
};
iframe.contentWindow.postMessage(message, 'https://utteranc.es');
}
}
// dynamic change
const observer = new MutationObserver((mutationsList, observer) => {
for (let mutation of mutationsList) {
if (mutation.type === 'attributes' && mutation.attributeName === 'data-theme') {
setUtterancesTheme();
}
}
});
observer.observe(document.documentElement, { attributes: true, childList: false, subtree: false });
let utterancesScript = document.createElement('script');
utterancesScript.async = true;
utterancesScript.src = 'https://utteranc.es/client.js';
utterancesScript.crossOrigin = 'anonymous';
utterancesScript.setAttribute('issue-term', '{{ site.utterances.issue_term }}');
utterancesScript.setAttribute('label', '{{ site.utterances.label }}');
utterancesScript.setAttribute('repo', '{{ site.utterances.repo }}');
utterancesScript.setAttribute('theme', utterancesThemeFromDataTheme());
const placeholder = document.getElementById('utterances-placeholder');
placeholder.parentNode.replaceChild(utterancesScript, placeholder);
</script>
{%- else -%}
<script async
crossorigin="anonymous"
issue-term="{{ site.utterances.issue_term }}"
label="{{ site.utterances.label }}"
repo="{{ site.utterances.repo }}"
src="https://utteranc.es/client.js"
theme="{{ site.utterances.theme }}">
</script>
{%- endif -%}

View file

@ -1,21 +0,0 @@
{% if include.selector %}
{% assign selector = include.selector %}
{% endif %}
{% if include.seed %}
{% assign seed = include.seed %}
{% endif %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/geopattern/1.2.3/js/geopattern.min.js"></script>
<script>
function setRandomBgImage(selector, seed) {
var pattern = GeoPattern.generate(seed);
var element = document.querySelector(selector)
if (element) {
element.style.backgroundImage = pattern.toDataUrl();
}
}
setRandomBgImage('{{ selector }}', '{{ seed }}');
</script>

View file

@ -1,19 +0,0 @@
<script>
function initGoogleAnalytics() {
var doNotTrack = (window.doNotTrack === "1" || navigator.doNotTrack === "1" ||
navigator.doNotTrack === "yes" || navigator.msDoNotTrack === "1");
var enableDNT = "{{ site.enableDNT | default: true }}" == "true";
if (!enableDNT || !doNotTrack) {
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', '{{ site.google_analytics }}', 'auto');
ga('send', 'pageview');
}
}
window.addEventListener("load", initGoogleAnalytics);
</script>

View file

@ -1,108 +0,0 @@
{% if include.translate_langs %}
{% assign translate_langs = include.translate_langs %}
{% endif %}
{% if include.lang %}
{% assign lang = include.lang %}
{% endif %}
<div id="google_translate_element" style="display: none;">
</div>
<span class="ct-language">
<ul class="list-unstyled ct-language-dropdown">
{% for item in translate_langs %}
<li>
<a href="#" class="lang-select" data-lang="{{ item.lang }}">
{% if item.img %}
<img src="{{ item.img }}" title="{{ item.text }}">
{% else %}
{{ item.text }}
{% endif %}
</a>
</li>
{% endfor %}
</ul>
</span>
<script type="text/javascript">
function googleTranslateElementInit() {
new google.translate.TranslateElement({
pageLanguage: '{{ lang }}',
autoDisplay: false,
layout: google.translate.TranslateElement.InlineLayout.VERTICAL
}, 'google_translate_element');
// Links to cross-origin destinations are unsafe
var gll = document.getElementsByClassName('goog-logo-link')[0];
if (gll) {
gll.setAttribute('rel', 'noopener');
}
function restoreLang() {
var iframe = document.getElementsByClassName('goog-te-banner-frame')[0];
if (!iframe) return;
var innerDoc = iframe.contentDocument || iframe.contentWindow.document;
var restore_el = innerDoc.getElementsByTagName("button");
for (var i = 0; i < restore_el.length; i++) {
if (restore_el[i].id.indexOf("restore") >= 0) {
restore_el[i].click();
var close_el = innerDoc.getElementsByClassName("goog-close-link");
close_el[0].click();
return;
}
}
}
function triggerHtmlEvent(element, eventName) {
var event;
if (document.createEvent) {
event = document.createEvent('HTMLEvents');
event.initEvent(eventName, true, true);
element.dispatchEvent(event);
} else {
event = document.createEventObject();
event.eventType = eventName;
element.fireEvent('on' + event.eventType, event);
}
}
var googleCombo = document.querySelector("select.goog-te-combo");
var langSelect = document.querySelector('.ct-language');
langSelect.addEventListener('click', function(event) {
if (!event.target) {
return;
}
var selected = document.querySelector('.ct-language .ct-language-selected');
if (selected) {
selected.classList.remove('ct-language-selected');
}
var target = event.target;
while (target && target !== langSelect ) {
if (target.matches('.lang-select')) {
break;
}
target = target.parentElement;
}
if (target && target.matches('.lang-select')) {
var lang = target.getAttribute('data-lang');
if (googleCombo.value == lang) {
restoreLang();
} else {
target.parentElement.classList.add('ct-language-selected');
googleCombo.value = lang;
triggerHtmlEvent(googleCombo, 'change');
}
}
event.preventDefault();
});
}
</script>
<script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>

View file

@ -1,44 +0,0 @@
<script>
function hashLocate(hashValue) {
hashValue = hashValue.replace(/^.*#h-/, '');
hashValue = decodeURIComponent(hashValue);
var element = document.getElementById(hashValue);
if (!element) {
return;
}
var header = document.querySelector('header.site-header');
var headerRect = header.getBoundingClientRect();
var headerTop = Math.floor(headerRect.top);
var headerHeight = Math.floor(headerRect.height);
var scrollPos = getScrollPos();
var offsetY = element.offsetTop - (headerTop + headerHeight + 20);
if (offsetY == scrollPos.y) {
return;
}
if (headerTop == 0 && offsetY > scrollPos.y) {
offsetY += headerHeight + 2;
} else if (headerTop < 0 && offsetY < scrollPos.y) {
offsetY -= headerHeight - 2;
}
smoothScrollTo(offsetY);
}
// The first event occurred
window.addEventListener('load', function(event) {
if (window.location.hash) {
hashLocate(window.location.hash);
}
});
// The first event occurred
window.addEventListener('click', function(event) {
if (event.target.tagName.toLowerCase() == 'a') {
hashLocate(event.target.getAttribute('href'));
}
});
</script>

View file

@ -1,10 +0,0 @@
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
inlineMath: [['$','$']]
}
});
</script>
<script
src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML" type="text/javascript"></script>

View file

@ -1,108 +0,0 @@
<div class="theme-toggle">
<input type="checkbox" id="theme-switch">
<label for="theme-switch">
<div class="toggle"></div>
<div class="names">
<p class="light">Light</p>
<p class="dark">Dark</p>
</div>
</label>
</div>
{%- assign name = 'night_mode' -%}
{%- include functions.html func='get_value' default='auto' -%}
{%- assign night_mode = return -%}
<script>
(function() {
var sw = document.getElementById('theme-switch');
var html = document.getElementsByTagName('html')[0];
var nightModeOption = ('{{ night_mode }}' || 'auto').toLowerCase();
var storage = nightModeOption === 'manual'
? localStorage
: sessionStorage;
var themeData = loadThemeData();
function saveThemeData(data) {
storage.setItem('theme', JSON.stringify(data));
}
function loadThemeData() {
var data = storage.getItem('theme');
try {
data = JSON.parse(data ? data : '');
} catch(e) {
data = { nightShift: undefined, autoToggleAt: 0 };
saveThemeData(data);
}
return data;
}
function handleThemeToggle(nightShift) {
themeData.nightShift = nightShift;
saveThemeData(themeData);
html.dataset.theme = nightShift ? 'dark' : 'light';
setTimeout(function() {
sw.checked = nightShift ? true : false;
}, 50);
}
function autoThemeToggle() {
// Next time point of theme toggle
var now = new Date();
var toggleAt = new Date();
var hours = now.getHours();
var nightShift = hours >= 19 || hours <=7;
if (nightShift) {
if (hours > 7) {
toggleAt.setDate(toggleAt.getDate() + 1);
}
toggleAt.setHours(7);
} else {
toggleAt.setHours(19);
}
toggleAt.setMinutes(0);
toggleAt.setSeconds(0);
toggleAt.setMilliseconds(0)
var delay = toggleAt.getTime() - now.getTime();
// auto toggle theme mode
setTimeout(function() {
handleThemeToggle(!nightShift);
}, delay);
return {
nightShift: nightShift,
toggleAt: toggleAt.getTime()
};
}
// Listen the theme toggle event
sw.addEventListener('change', function(event) {
handleThemeToggle(event.target.checked);
});
if (nightModeOption == 'auto') {
var data = autoThemeToggle();
// Toggle theme by local setting
if (data.toggleAt > themeData.autoToggleAt) {
themeData.autoToggleAt = data.toggleAt;
handleThemeToggle(data.nightShift);
} else {
handleThemeToggle(themeData.nightShift);
}
} else if (nightModeOption == 'manual') {
handleThemeToggle(themeData.nightShift);
} else {
var nightShift = themeData.nightShift;
if (nightShift === undefined) {
nightShift = nightModeOption === 'on';
}
handleThemeToggle(nightShift);
}
})();
</script>

View file

@ -1,26 +0,0 @@
{% if include.selector %}
{% assign selector = include.selector %}
{% endif %}
{% if include.seed %}
{% assign seed = include.seed %}
{% endif %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/trianglify/2.0.0/trianglify.min.js"></script>
<script>
function setRandomBgImage(selector, seed, zoom) {
var element = document.querySelector(selector);
if (!element) return;
var pattern = Trianglify({
width: screen.width * zoom,
height: element.offsetHeight * zoom,
seed: seed
});
var image = document.createElement("div");
image.style.backgroundImage = "url(" + pattern.png() + ")";
element.appendChild(image);
}
setRandomBgImage('{{ selector }}', '{{ seed }}', {{ zoom | default: 1}});
</script>

View file

@ -1,30 +0,0 @@
{%- assign params = include -%}
{%- if params.func -%}
{%- assign func = params.func -%}
{%- endif -%}
{%- assign include_path = func -%}
{%- assign path_array = include_path | split: '.' -%}
{%- if path_array.size == 1 -%}
{%- assign include_path = include_path | append: '.html' -%}
{%- endif -%}
{%- if func == 'log' -%}
{%- include functions/log.html level=include.level msg=include.msg -%}
{%- else -%}
{%- assign include_path = 'functions/' | append: include_path -%}
{%- include {{ include_path }} params=params-%}
{%- endif -%}
{%- if return == nil -%}
{%- assign return = include.default -%}
{%- endif -%}
{%- if func != 'log' -%}
{%- assign msg = '[function]['
| append: {{func}}
| append: '] '
| append: {{return}}
-%}
{%- include functions.html func='log' level='info' -%}
{%- endif -%}

View file

@ -1,39 +0,0 @@
{% if include.params.article %}
{% assign article = include.params.article %}
{% endif %}
{% if include.params.lang %}
{% assign lang = include.params.lang %}
{% else %}
{% assign lang = lang | default: site.lang | default: "en" %}
{% endif %}
{% if include.params.excerpt_size %}
{% assign excerpt_size = include.params.excerpt_size %}
{% else %}
{% assign excerpt_size = excerpt_size
| default: site.excerpt_size
| default: 350 %}
{% endif %}
{%- include functions.html func='get_article_words' -%}
{% assign words = return %}
{% assign _article = article | strip_html %}
{% assign _words = _article | size %}
{% assign _size = excerpt_size %}
{% if lang != "en" %}
{% assign _size = words
| times: 1.0
| divided_by: _words
| times: _size
| round %}
{% endif %}
{% if _size > excerpt_size %}
{% assign _size = excerpt_size %}
{% endif %}
{% assign return = _article | truncate: _size %}

View file

@ -1,26 +0,0 @@
{% if include.params.article %}
{% assign article = include.params.article %}
{% endif %}
{% if include.params.lang %}
{% assign lang = include.params.lang %}
{% else %}
{% assign lang = lang | default: site.lang | default: "en" %}
{% endif %}
{% assign words = article | number_of_words %}
{% if lang != "en" %}
{% assign words = words
| times: 0.6
| round %}
{% assign words = article
| strip_html
| strip_newlines
| size
| times: 0.4
| plus: words
| round %}
{% endif %}
{% assign return = words %}

View file

@ -1,68 +0,0 @@
{%- include functions.html func='log' level='debug' msg='Get banner value' -%}
{% assign name = 'banner' %}
{%- include functions.html func='get_value' -%}
{% assign banner = return %}
{%- if banner.first -%}
{%- include functions.html func='log' level='debug' msg='Get banner_image value' -%}
{% assign name = 'banner.image' %}
{%- include functions.html func='get_value' -%}
{% assign banner_image = return | relative_url %}
{%- else -%}
{% assign banner_image = banner | relative_url %}
{%- endif -%}
{%- include functions.html func='log' level='debug' msg='Get banner_background value' -%}
{% assign name = 'banner.background' %}
{%- include functions.html func='get_value' -%}
{% assign banner_background = return %}
{%- include functions.html func='log' level='debug' msg='Get banner_opacity value' -%}
{% assign name = 'banner.opacity' %}
{%- include functions.html func='get_value' -%}
{% assign banner_opacity = return %}
{%- include functions.html func='log' level='debug' msg='Get banner_height value' -%}
{% assign name = 'banner.height' %}
{%- include functions.html func='get_value' -%}
{% assign banner_height = return %}
{%- include functions.html func='log' level='debug' msg='Get banner_min_height value' -%}
{% assign name = 'banner.min_height' %}
{%- include functions.html func='get_value' -%}
{% assign banner_min_height = return %}
{%- include functions.html func='log' level='debug' msg='Get banner_heading_style value' -%}
{% assign name = 'banner.heading_style' %}
{%- include functions.html func='get_value' -%}
{% assign banner_heading_style = return %}
{%- include functions.html func='log' level='debug' msg='Get banner_subheading_style value' -%}
{% assign name = 'banner.subheading_style' %}
{%- include functions.html func='get_value' -%}
{% assign banner_subheading_style = return %}
{%- include functions.html func='log' level='debug' msg='Get banner_video value' -%}
{% assign name = 'banner.video' %}
{%- include functions.html func='get_value' -%}
{% assign banner_video = return %}
{%- include functions.html func='log' level='debug' msg='Get banner_loop value' -%}
{% assign name = 'banner.loop' %}
{%- include functions.html func='get_value' default=true -%}
{% assign banner_loop = return %}
{%- include functions.html func='log' level='debug' msg='Get banner_volume value' -%}
{% assign name = 'banner.volume' %}
{%- include functions.html func='get_value' default=0 -%}
{% assign banner_volume = return %}
{%- include functions.html func='log' level='debug' msg='Get banner_start_at value' -%}
{% assign name = 'banner.start_at' %}
{%- include functions.html func='get_value' default=0 -%}
{% assign banner_start_at = return %}
{% if banner_image or banner_video %}
{% assign has_banner = true %}
{% endif %}

View file

@ -1,12 +0,0 @@
{% assign split_mark = '<|>' %}
{% assign categories = '' %}
{% for category in site.categories %}
{% assign name = category | first %}
{% assign categories = categories | append: split_mark | append: name %}
{% endfor %}
{% assign return = categories
| remove_first: split_mark
| split: split_mark
| sort: self %}

View file

@ -1,18 +0,0 @@
{% if include.params.filter %}
{% assign filter = include.params.filter %}
{% endif %}
{% assign split_mark = '<|>' %}
{% assign dates = '' %}
{% for post in site.posts %}
{% assign name = post.date | date: filter %}
{% assign dates = dates | append: split_mark | append: name %}
{% endfor %}
{% assign return = dates
| remove_first: split_mark
| split: split_mark
| sort: self
| uniq %}

View file

@ -1,49 +0,0 @@
{% if include.params.article %}
{% assign article = include.params.article %}
{% endif %}
{% if include.params.lang %}
{% assign lang = include.params.lang %}
{% else %}
{% assign lang = lang | default: site.lang | default: "en" %}
{% endif %}
{% if include.params.speed %}
{% assign speed = include.params.speed %}
{% else %}
{% assign speed = 160 %}
{% endif %}
{%- include functions.html func='get_article_words' -%}
{% assign words = return %}
{% assign total_mins = words
| divided_by: speed
| at_least: 1 %}
{% assign hours = total_mins | divided_by: 60 %}
{% assign mins = total_mins | modulo: 60 %}
{% assign return = "About" %}
{% if hours > 0 %}
{% assign unit = "hour" %}
{% if hours > 1 %}
{% assign unit = unit | append: "s" %}
{% endif %}
{% assign return = return
| append: " "
| append: hours
| append: " "
| append: unit %}
{% endif %}
{% assign unit = "min" %}
{% if mins > 1 %}
{% assign unit = unit | append: "s" %}
{% endif %}
{% assign return = return
| append: " "
| append: mins
| append: " "
| append: unit %}

View file

@ -1,12 +0,0 @@
{% assign split_mark = '<|>' %}
{% assign tags = '' %}
{% for tag in site.tags %}
{% assign name = tag | first %}
{% assign tags = tags | append: split_mark | append: name %}
{% endfor %}
{% assign return = tags
| remove_first: split_mark
| split: split_mark
| sort: self %}

View file

@ -1,42 +0,0 @@
{%- if include.params.name -%}
{%- assign name = include.params.name -%}
{%- endif -%}
{%- assign return = nil -%}
{%- assign keys = name | split:'.' -%}
{%- assign name = keys.first -%}
{%- assign keys = keys | shift -%}
{%- for step in (1..7) -%}
{%- case step -%}
{%- when 1 -%}
{%- assign return = page[name] -%}
{%- when 2 -%}
{%- assign return = site[name] -%}
{%- when 3 -%}
{%- assign return = site.data[name] -%}
{%- when 4 -%}
{%- assign return = site.defaults[page.layout][name] -%}
{%- when 5 -%}
{%- assign return = site.data.defaults[page.layout][name] -%}
{%- when 6 -%}
{%- assign return = layout[name] -%}
{%- else -%}
{%- assign return = include.params.default -%}
{%- endcase -%}
{%- for key in keys -%}
{%- assign return = return[key] -%}
{%- if return == nil -%}
{%- break -%}
{%- endif -%}
{%- endfor -%}
{%- if return != nil -%}
{%- break -%}
{%- endif -%}
{%- endfor -%}

View file

@ -1,17 +0,0 @@
{% if include.params.level %}
{% assign level = include.params.level %}
{% endif %}
{% if include.params.msg %}
{% assign msg = include.params.msg %}
{% endif %}
{% if site.debug == true %}
{% if level == 'debug' %}
{% if jekyll.environment == "development" %}
<!-- {{ msg }} -->
{% endif %}
{% else %}
<!-- {{ msg }} -->
{% endif %}
{% endif %}

View file

@ -1,18 +0,0 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="google-translate-customization" content="108d9124921d80c3-80e20d618ff053c8-g4f02ec6f3dba68b7-c">
{%- seo -%}
<link rel="shortcut icon" href="{{ site.favicon }}">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/typeface-noto-sans@0.0.72/index.min.css">
<link rel="stylesheet" href="{{ "/assets/css/main.css" | relative_url }}">
<script src="{{ "/assets/js/main.js" | relative_url }}"></script>
{%- feed_meta -%}
{%- if jekyll.environment == 'production' and site.google_analytics -%}
{%- include extensions/google-analytics.html -%}
{%- endif -%}
{%- include extensions/code-highlight.html -%}
{%- include custom-head.html -%}
</head>

View file

@ -1,10 +0,0 @@
{%- include functions.html func='log' level='debug' msg='Get datetimes value' -%}
{% assign filter = '%Y' %}
{% include functions.html func='get_datetimes' %}
{% assign datetimes = return %}
{% assign keys = datetimes %}
{% assign field = 'date' %}
{% assign url = '/archives.html' | relative_url %}
{% include sidebar/common-list.html %}

View file

@ -1,122 +0,0 @@
<style type="text/css" media="screen">
.post-menu ul {
list-style: none;
padding: 0;
margin: 0;
}
</style>
<div class="post-menu">
<div class="post-menu-title">TOC</div>
<div class="post-menu-content"></div>
</div>
<script>
function generateContent() {
var menu = document.querySelector(".post-menu");
var menuContent = menu.querySelector(".post-menu-content");
var headings = document.querySelector(".post-content").querySelectorAll("h2, h3, h4, h5, h6");
// Hide menu when no headings
if (headings.length === 0) {
return menu.style.display = "none";
}
// Generate post menu
var menuHTML = '';
for (var i = 0; i < headings.length; i++) {
var h = headings[i];
menuHTML += (
'<li class="h-' + h.tagName.toLowerCase() + '">'
+ '<a href="#h-' + h.getAttribute('id') + '">' + h.textContent + '</a></li>');
}
menuContent.innerHTML = '<ul>' + menuHTML + '</ul>';
// The header element
var header = document.querySelector('header.site-header');
function doMenuCollapse(index, over_items) {
var items = menuContent.firstChild.children;
if (over_items == undefined) {
over_items = 20;
}
if (items.length < over_items) {
return;
}
var activeItem = items[index];
var beginItem = activeItem
var endItem = activeItem
var beginIndex = index;
var endIndex = index + 1;
while (beginIndex >= 0
&& !items[beginIndex].classList.contains('h-h2')) {
beginIndex -= 1;
}
while (endIndex < items.length
&& !items[endIndex].classList.contains('h-h2')) {
endIndex += 1;
}
for (var i = 0; i < beginIndex; i++) {
item = items[i]
if (!item.classList.contains('h-h2')) {
item.style.display = 'none';
}
}
for (var i = beginIndex + 1; i < endIndex; i++) {
item = items[i]
// if (!item.classList.contains('h-h2')) {
item.style.display = '';
// }
}
for (var i = endIndex; i < items.length; i++) {
item = items[i]
if (!item.classList.contains('h-h2')) {
item.style.display = 'none';
}
}
}
// Init menu collapsed
doMenuCollapse(-1);
// Active the menu item
window.addEventListener('scroll', function (event) {
var lastActive = menuContent.querySelector('.active');
var changed = true;
var activeIndex = -1;
for (var i = headings.length - 1; i >= 0; i--) {
var h = headings[i];
var headingRect = h.getBoundingClientRect();
var headerRect = header.getBoundingClientRect();
var headerTop = Math.floor(headerRect.top);
var headerHeight = Math.floor(headerRect.height);
var headerHeight = headerTop + headerHeight + 20;
if (headingRect.top <= headerHeight) {
var id = 'h-' + h.getAttribute('id');
var a = menuContent.querySelector('a[href="#' + id + '"]');
var curActive = a.parentNode;
if (curActive) {
curActive.classList.add('active');
activeIndex = i;
}
if (lastActive == curActive) {
changed = false;
}
break;
}
}
if (changed) {
if (lastActive) {
lastActive.classList.remove('active');
}
doMenuCollapse(activeIndex);
}
event.preventDefault();
});
}
generateContent();
</script>

View file

@ -1,9 +0,0 @@
{%- include functions.html func='log' level='debug' msg='Get categories value' -%}
{%- include functions.html func='get_categories' -%}
{% assign categories = return %}
{% assign keys = categories %}
{% assign field = 'categories' %}
{% assign url = '/categories.html' | relative_url %}
{% include sidebar/common-list.html %}

View file

@ -1,25 +0,0 @@
{%- if include.keys -%}
{%- assign keys = include.keys -%}
{%- endif -%}
{%- if include.field -%}
{%- assign field = include.field -%}
{%- endif -%}
<div class="common-list">
<ul>
<li>
<a href="{{ '/index.html' | relative_url }}">
All<span>{{ site.posts.size }}</span>
</a>
</li>
{% for key in keys %}
<li>
<a href="{{ url }}#h-{{ key }}">
{{ key }} <span>{{ site.posts | where: field, key | size }}</span>
</a>
</li>
{% endfor %}
</ul>
</div>

View file

@ -1,3 +0,0 @@
<div>
{%- include extensions/google-translate.html -%}
</div>

View file

@ -1,9 +0,0 @@
{%- include functions.html func='log' level='debug' msg='Get tags value' -%}
{%- include functions.html func='get_tags' -%}
{% assign tags = return %}
{% assign keys = tags %}
{% assign field = 'tags' %}
{% assign url = '/tags.html' | relative_url %}
{%- include sidebar/common-list.html -%}

View file

@ -1,9 +0,0 @@
<article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">
<div class="post-content e-content" itemprop="articleBody">
{{ content }}
</div>
</article>

View file

@ -1,131 +0,0 @@
{%- include functions.html func='log' level='debug' msg='Get banner_html value' -%}
{% assign name = 'banner_html' %}
{%- include functions.html func='get_value' -%}
{% assign banner_html = return %}
{%- include functions.html func='log' level='debug' msg='Get heading value' -%}
{% assign name = 'heading' %}
{%- include functions.html func='get_value' -%}
{% assign heading = return %}
{%- include functions.html func='log' level='debug' msg='Get subheading value' -%}
{% assign name = 'subheading' %}
{%- include functions.html func='get_value' -%}
{% assign subheading = return %}
{%- include functions.html func='get_banner' -%}
{%- if has_banner -%}
{%- if banner_background -%}
<style>
html .page-banner {
background: {{ banner_background }};
}
</style>
{%- endif -%}
{%- if banner_height -%}
<style>
{%- assign num = banner_height | times: 1 -%}
{%- assign unit = banner_height | replace_first: num -%}
{%- assign banner_min_height = banner_min_height | default: banner_height -%}
html .page-banner {
height: {{ banner_height | times: 0.368 | append: unit }};
min-height: {{ banner_min_height }};
}
html[data-scroll-status="top"] .page-banner {
height: {{ banner_height }};
}
</style>
{%- endif -%}
{%- if banner_opacity -%}
<style>
html .page-banner .page-banner-img > *:first-child {
opacity: {{ banner_opacity }};
}
html[data-theme="dark"] .page-banner .page-banner-img > *:first-child {
opacity: {{ banner_opacity | times: 0.718 }};
}
</style>
{%- endif -%}
{%- if banner_heading_style -%}
<style>
html .page-banner .page-banner-inner > *:first-child > *:nth-child(1) {
{{ banner_heading_style }}
}
</style>
{%- endif -%}
{%- if banner_subheading_style -%}
<style>
html .page-banner .page-banner-inner > *:first-child > *:nth-child(2) {
{{ banner_subheading_style }}
}
</style>
{%- endif -%}
<section class="page-banner">
<div class="page-banner-img">
{%- if banner_video -%}
<video
autoplay=""
poster="{{ banner_image }}"
playsinline
>
<source src="{{ banner_video }}">
</video>
<script>
(function() {
var video = document.querySelector('.page-banner .page-banner-img > video');
var videoPlay = function() {
video.play().catch (function() {
video.muted = true;
video.play();
});
}
video.onloadstart = function() {
video.currentTime = {{ banner_start_at }};
video.volume = {{ banner_volume }};
video.muted = (video.volume == 0);
videoPlay();
}
video.onended = function() {
video.currentTime = {{ banner_start_at }};
video.volume = 0;
{%- if banner_loop -%}
video.play();
{%- endif -%}
}
})();
</script>
{%- else -%}
<div style="background-image: url({{ banner_image }})"></div>
<img class="img-placeholder" src="{{ banner_image }}">
{%- endif -%}
</div>
<div class="wrapper">
<div class="page-banner-inner">
{%- if banner_html -%}
{%- assign banner_html = 'views/' | append: banner_html -%}
{%- include {{ banner_html }} -%}
{%- else -%}
<div class="page-banner-default">
<h1 class="page-banner-heading">
{{ heading | default: page.title | escape }}
</h1>
<h2 class="page-banner-subheading">
{{ subheading | default: page.subtitle | escape }}
</h2>
</div>
{%- endif -%}
</div>
</div>
</section>
{%- endif -%}

View file

@ -1,22 +0,0 @@
<footer class="site-footer h-card">
<data class="u-url" href="{{ "/" | relative_url }}"></data>
<div class="wrapper">
<div class="site-footer-inner">
{%- assign currentYear = 'now' | date: "%Y" -%}
{%- assign copyright = site.copyright
| replace: '{currentYear}', currentYear
| replace: '{author}', site.author
| replace: '(c)', '&copy;'
| replace: '(p)', '℗'
| replace: '(cleft)', '<span class="copyleft">&copy;</span>'
-%}
<div>{{ copyright }}</div>
<div>Powered by <a title="Jekyll is a simple, blog-aware, static site
generator." href="https://jekyllrb.com/">Jekyll</a> &amp; <a title="Yat, yet
another theme." href="https://github.com/jeffreytse/jekyll-theme-yat">Yat Theme</a>.</div>
<div><a rel="me" href="https://social.linux.pizza/@hernik">Mastodon</a></div>
<div class="footer-col rss-subscribe">Subscribe <a href="{{ "/feed.xml" | relative_url }}">via RSS</a></div>
</div>
</div>
</footer>

View file

@ -1,95 +0,0 @@
{%- include functions.html func='get_banner' -%}
{%- include functions.html func='log' level='debug' msg='Get header_transparent value' -%}
{%- assign name = 'header_transparent' -%}
{%- include functions.html func='get_value' default=true -%}
{%- assign header_transparent = return -%}
{%- if has_banner and header_transparent -%}
{%- assign header_transparent_class = "site-header-transparent" -%}
{%- endif -%}
<header class="site-header {{ header_transparent_class }}" role="banner">
<div class="wrapper">
<div class="site-header-inner">
{%- assign default_paths = site.pages | where: "dir", "/" | map: "path" -%}
{%- assign page_paths = site.header_pages | default: default_paths -%}
<span class="site-brand">
{%- include views/site-brand.html -%}
</span>
{%- if page_paths -%}
<nav class="site-nav">
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
<label for="nav-trigger">
<span class="menu-icon">
<svg viewBox="0 0 18 15" width="18px" height="15px">
<path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"/>
</svg>
</span>
</label>
<div class="trigger">
{%- for path in page_paths -%}
{%- assign my_page = site.pages | where: "path", path | first -%}
{%- if my_page.title -%}
<a class="page-link" href="{{ my_page.url | relative_url }}">{{ my_page.title | upcase | escape }}</a>
{%- endif -%}
{%- endfor -%}
{%- assign name = 'translate_langs' -%}
{%- include functions.html func='get_value' -%}
{%- assign translate_langs = return -%}
{%- if translate_langs.size > 0 -%}
{%- assign name = 'lang' -%}
{%- include functions.html func='get_value' default='en' -%}
{%- assign lang = return -%}
<span class="page-link">
{%- include extensions/google-translate.html -%}
</span>
{%- endif -%}
</div>
</nav>
{%- endif -%}
</div>
</div>
</header>
<script>
function initHeader() {
var lastScrollY = getScrollPos().y;
var documentElement = document.documentElement;
function storeScrollData() {
var y = getScrollPos().y;
{%- if banner and header_transparent -%}
documentElement.setAttribute("data-header-transparent", "");
{%- endif -%}
var scrollStatus = "";
if (y <= 0) {
scrollStatus = "top";
} else if ((window.innerHeight + y) >= document.body.offsetHeight) {
scrollStatus = "bottom";
} else {
var isScrollDown = (y - lastScrollY > 0) ? true : false;
scrollStatus = isScrollDown ? "down" : "up";
}
lastScrollY = y;
documentElement.setAttribute("data-scroll-status", scrollStatus);
}
window.addEventListener('scroll', function(e) {
storeScrollData();
});
storeScrollData();
}
document.addEventListener('DOMContentLoaded', initHeader);
</script>

View file

@ -1,51 +0,0 @@
{%- if page.paginator -%}
{%- assign paginator = page.paginator -%}
{%- elsif paginator == nil -%}
{%- assign paginator = site -%}
{%- endif -%}
{%- if paginator.posts.size > 0 -%}
<div class="pagination">
<!-- Post list links -->
<ul class="post-list">
{%- for post in paginator.posts -%}
<li>
{%- assign date_format = site.yat.date_format | default: "%b %-d, %Y" -%}
{% assign article = post.content %}
{% assign lang = post.lang %}
{%- include functions.html func='get_reading_time' -%}
{% assign reading_time = return %}
{%- include functions.html func='get_article_excerpt' -%}
{% assign excerpt = return %}
{%- assign post_url = post.url | relative_url -%}
<h2 class="post-title">
<a class="post-link" href="{{ post_url }}">
{{ post.title | escape }}
</a>
</h2>
<div class="post-meta">
<span class="post-date"><i class="fa fa-calendar"></i> {{ post.date | date: date_format }}</span>
<span class="post-reading-time left-vsplit"><i class="fa fa-clock-o"></i> {{ reading_time }}</span>
</div>
<a class="post-excerpt" href="{{ post_url }}">
<p>
{{ excerpt }} <span class="read_more">Read More</span>
</p>
</a>
<div class="post-tags">
{%- for tag in post.tags -%}
<a class="post-tag" href="{{ '/tags.html ' | relative_url }}#{{tag}}">#{{tag}}</a>
{%- endfor -%}
</div>
</li>
{%- endfor -%}
</ul>
<!-- Pagination links -->
{%- if paginator.posts.size < site.posts.size -%}
{%- include views/paginator.html -%}
{%- endif -%}
</div>
{%- endif -%}

View file

@ -1,25 +0,0 @@
{% if include.paginator %}
{% assign paginator = include.paginator %}
{% endif %}
{% if paginator.posts.size > 0 %}
<div class="paginator">
<span class="previous">
{% if paginator.previous_page %}
<a href="{{ paginator.previous_page_path | relative_url }}">Prev</a>
{% else %}
<span>Prev</span>
{% endif %}
</span>
<span class="indicator"> {{ paginator.page }}/{{ paginator.total_pages }}</span>
<span class="next">
{% if paginator.next_page %}
<a href="{{ paginator.next_page_path | relative_url }}">Next</a>
{% else %}
<span>Next</span>
{% endif %}
</span>
</div>
{% endif %}

View file

@ -1,26 +0,0 @@
<header class="post-header">
<h1 class="post-title p-name" itemprop="name headline">{{ heading | default: page.title | escape }}</h1>
<h2 class="post-subtitle">{{ subheading | default: page.subtitle | escape }}</h2>
<p class="post-meta">
<time class="dt-published" datetime="{{ page.date | date_to_xmlschema }}" itemprop="datePublished">
{%- assign date_format = site.yat.date_format | default: "%b %-d, %Y" -%}
<i class="fa fa-calendar"></i> {{ page.date | date: date_format }}
</time>
{% assign article = page.content %}
{% assign lang = page.lang %}
{%- include functions.html func='get_reading_time' -%}
{% assign reading_time = return %}
<span class="post-reading-time left-vsplit"><i class="fa fa-clock-o"></i> {{ reading_time }}</span>
</p>
{%- if page.tags.size > 0 -%}
<div class="post-tags">
{%- for tag in page.tags -%}
<a class="post-tag" href="{{ '/tags.html ' | relative_url }}#{{tag}}">#{{tag}}</a>
{%- endfor -%}
</div>
{%- endif -%}
</header>

View file

@ -1,13 +0,0 @@
{%- if include.item -%}
{%- assign item = include.item -%}
{%- endif -%}
{%- assign post = item -%}
{% assign date_format = site.yat.date_format | default: "%b %-d, %Y" %}
<span class="post-meta">{{ post.date | date: date_format }}</span>
<span>
<a class="post-link" href="{{ post.url | relative_url }}">
{{ post.title | escape }}
</a>
</span>

View file

@ -1,21 +0,0 @@
{%- if include.keys -%}
{%- assign keys = include.keys -%}
{%- endif -%}
{%- if include.field -%}
{%- assign field = include.field -%}
{%- endif -%}
<div class="page-segments">
<ul class="page-segments-list">
{% for key in keys %}
<h2 id="{{ key }}" class="segment-name">{{ key }}</h2>
{% assign items = site.posts | where: field, key %}
{% for item in items %}
{% if item != nil %}
<li> {% include views/post-item.html %} </li>
{% endif %}
{% endfor %}
{% endfor %}
</ul>
</div>

View file

@ -1,4 +0,0 @@
<a class="site-brand-inner" rel="author" href="{{ "/" | relative_url }}">
<img class="site-favicon" title="{{ site.title | escape }}" src="{{ site.favicon }}" onerror="this.style.display='none'">
{{ site.title | escape }}
</a>

View file

@ -1,24 +0,0 @@
---
layout: default
---
<style type="text/css" media="screen">
.container {
margin: 10px auto;
max-width: 600px;
text-align: center;
}
h1 {
margin: 30px 0;
font-size: 4em;
line-height: 1;
letter-spacing: -1px;
}
</style>
<div class="container">
<h1>404</h1>
<p><strong>Page not found :(</strong></p>
<p>Try to check other pages through the menu. </p>
</div>

View file

@ -1,9 +0,0 @@
---
layout: post
hidden:
- header
- navigator
- related_posts
---
{{ content }}

View file

@ -1,18 +0,0 @@
---
layout: framework
sidebar: archive-list
---
{%- if site.posts.size > 0 -%}
{% include functions.html func='log' level='debug' msg='Get datetimes value' %}
{% assign filter = '%Y' %}
{% include functions.html func='get_datetimes' %}
{% assign datetimes = return %}
{% assign keys = datetimes | reverse %}
{% assign field = 'date' %}
{% include views/segments.html %}
{%- endif -%}

View file

@ -1,14 +0,0 @@
---
layout: framework
sidebar: category-list
---
<div class="articles">
{% if page.banner == nil %}
{% assign banner = page.title %}
{% endif %}
{{ content }}
{% include views/pagination.html %}
</div>

View file

@ -1,16 +0,0 @@
---
layout: framework
sidebar: category-list
---
{%- if site.posts.size > 0 -%}
{%- include functions.html func='log' level='debug' msg='Get value' -%}
{%- include functions.html func='get_categories' -%}
{% assign categories = return %}
{% assign keys = categories %}
{% assign field = 'categories' %}
{%- include views/segments.html -%}
{%- endif -%}

View file

@ -1,27 +0,0 @@
<!DOCTYPE html>
<html lang="{{ page.lang | default: site.lang | default: "en" }}">
{%- include head.html -%}
<body>
{%- include views/header.html -%}
{%- include views/banner.html -%}
{%- include extensions/hashlocate.html -%}
{%- include extensions/theme-toggle.html -%}
{%- include extensions/click-to-top.html -%}
<main class="page-content" aria-label="Content">
<div class="wrapper">
{{ content }}
</div>
</main>
{%- include views/footer.html -%}
</body>
</html>

View file

@ -1,35 +0,0 @@
---
layout: default
---
<div class="framework">
<section class="main">
{{ content }}
</section>
<section class="sidebar" style="margin-left: 15px;">
<!-- Get sidebar items -->
{%- if page.sidebar -%}
{%- assign sidebar = page.sidebar -%}
{%- elsif site.defaults[page.layout].sidebar -%}
{%- assign sidebar = site.defaults[page.layout].sidebar -%}
{%- elsif layout.sidebar -%}
{%- assign sidebar = layout.sidebar -%}
{%- endif -%}
{%- for item in sidebar -%}
{%- assign file = item -%}
{%- assign array = file | split: '.' -%}
{%- if array.size == 1 -%}
{%- assign file = file | append: '.html' -%}
{%- endif -%}
{%- assign file = 'sidebar/' | append: file -%}
{%- include {{ file }} %}
{%- endfor -%}
</section>
</div>

View file

@ -1,8 +0,0 @@
---
layout: articles
heading: 'Your awesome heading'
subheading: 'Your awesome subheading'
banner: 'default'
---
{{ content }}

View file

@ -1,77 +0,0 @@
---
layout: framework
banner:
banner_html: post-header.html
hidden: []
sidebar:
- article-menu
---
<div class="post">
<section>
{%- assign name = 'banner' -%}
{%- include functions.html func='get_value' -%}
{%- assign banner = return -%}
{%- assign name = 'hidden' -%}
{%- include functions.html func='get_value' -%}
{%- assign hidden = return -%}
{%- assign result = hidden | where_exp: "item", "item == 'header'" -%}
{%- if banner == nil and result.size == 0 -%}
{%- include views/post-header.html -%}
{%- endif -%}
{%- include views/article.html -%}
{%- assign result = hidden | where_exp: "item", "item == 'navigator'" -%}
{%- if result.size == 0 -%}
<div class="post-nav">
{%- if page.previous -%}
<a class="previous" href="{{ page.previous.url | relative_url }}" title="{{
page.previous.title | escape }}">{{ page.previous.title | escape | truncatewords: 6 }}</a>
{%- else -%}
<span></span>
{%- endif -%}
{%- if page.next -%}
<a class="next" href="{{ page.next.url | relative_url }}" title="{{ page.next.title | escape }}">{{ page.next.title | escape | truncatewords: 6 }}</a>
{%- else -%}
<span></span>
{%- endif -%}
</div>
{%- endif -%}
{%- assign result = hidden | where_exp: "item", "item == 'related_posts'" -%}
{%- if result.size == 0 -%}
<div class="post-related">
<div>Related Articles</div>
<ul>
{% assign posts = site[page.collection] | sample:4 %}
{%- for post in posts -%}
<li><a class="post-link" href="{{post.url | relative_url}}" title="{{ page.next.title | escape }}">{{ post.title | escape | truncatewords: 12 }}</a></li>
{%- endfor -%}
</ul>
</div>
{%- endif -%}
{%- assign result = hidden | where_exp: "item", "item == 'comments'" -%}
{%- if result.size == 0 -%}
<div class="post-comments">
{%- if page.comments != false -%}
{%- if site.disqus.shortname -%}
{%- include extensions/comments/disqus.html -%}
{%- endif -%}
{%- if site.utterances.repo -%}
{%- include extensions/comments/utterances.html -%}
{%- endif -%}
{%- endif -%}
</div>
{%- endif -%}
</section>
</div>

View file

@ -1,16 +0,0 @@
---
layout: framework
sidebar: tag-list
---
{%- if site.posts.size > 0 -%}
{%- include functions.html func='log' level='debug' msg='Get tags value' -%}
{%- include functions.html func='get_tags' -%}
{% assign tags = return %}
{% assign keys = tags %}
{% assign field = 'tags' %}
{%- include views/segments.html -%}
{%- endif -%}

View file

@ -1,24 +0,0 @@
---
layout: post
title: Automatizace, automatizace, automatizace
subtitle: Ulehčujeme si život
categories: programování
tags: automatizace technologie
sidebar: []
---
Roboti nám brzo vezmou práci, ale mně to (prozatím) nevadí. Já nechávám robůtky pracovat za mě a ulehčovat mi práci. A vy byste měli taky! Pokud teda programujete, jinak nevím.
Nedávno jsem objevil krásy zvané GitHub Actions a musím říct, že je to opravdu radost. Nikdy předtím jsem nedokázal pochopit jejich praktičnost, než jsem pracoval na [OpenCanteen](https://github.com/hernikplays/opencanteen). Sestavovat, podepisovat a nahrávat mě opravdu nebavilo a ještě s mým pomalým PC v kombinaci s pomalým internetem to nešlo zrovna rychle. Pak jsem si vzpomněl na GitHub Actions. Místo toho, abych dělal cokoliv produktivního, jsem strávil celé odpoledne nastavováním Actions, aby mi při novém tagu automaticky sestavil a publikoval vydání aplikace do Google Play.
Ta první část šla skvěle, avšak nahrávání do Google Play bylo o něco složitější, dokud jsem neobjevil hotové a, prozatím bezplatné, řešení [CodeMagic](https://codemagic.io/start/).
Jednoduše jsem napojil repozitář, nastavil podepisovací a nahrávací údaje a všechno hned jelo! Byla to radost pro někoho tak líného jako jsem já. I přesto, že jsem sám reálně nic neudělal, cítil jsem, že jsem dosáhl něčeho úžasného.
A určitě to lze dotáhnout ještě dál, už teď používám Actions pro automatickou analýzu kódu, a kdybych si vytvořil testy tak by mi to určitě i otestovalo celou aplikaci.
Pak jsem si řekl, že by možná mohl někdo chtít do mé aplikace přispět svým kódem. Protože chci v tom mít pořádek, hned jsem začal projíždět GitHub Marketplace pro nějaké akce na pull requesty. Hned jsem jich několik objevil.
Velice jsem ocenil akci, která mi automaticky přidala labely podle souboru, který byl v PR upraven.
Určitě nepotřebujete nutně automatizovat všechno, pokud máte např. soukromý či malý projekt. Nicméně si to můžete aspoň otestovat a případně využít v budoucnu tak se do toho pusťte! Automatizovat můžete všechno možné. Určitě budete mít dobrý pocit, když se vaše akce spustí a úspěšně se dokončí.

View file

@ -1,34 +0,0 @@
---
layout: post
title: GitHub Codespaces aneb VS Code na VPS
subtitle: Dopřejte si trochu luxusu
categories: vychytávky
tags: github vps
sidebar: []
---
Nedávno mi přišel e-mail, že jsem byl přidán do beta testování funkce Codespaces na GitHubu. Stručně, Codespaces má být systém ve kterém si vytvoříte vlastní prostředí pro váš repozitář, do kterého si nainstalujete všechny potřebné knihovny, SDK a balíky. Server, na kterém to všechno běží, si platíte u GitHubu a můžete na něj kdekoliv a kdykoliv přejít přes web do webové, narozdíl od výchozího webového VS Code plně vybavené, verzi VS Code nebo nainstalovaný VS Code a upravovat nebo testovat kód.
Hodí se pro lidi, kteří nechtějí tahat např. do školy nebo do práce, kde nesmí instalovat externí aplikace, svůj vlastní notebook.
Parametry
V betě je možné testovat pouze výchozí možnost 4 jádra + 8GB RAM + 32GB úložiště, což definitivně stačí pro osobní a malé projekty. Do konce bety neplatíte nic, ale 4 jádra vyjdou na $0.36 (asi 8,3 kč) za hodinu, tj za hodinu aktivního používání. Codespace se vám automaticky vypne, pokud není po stanovenou dobu nepoužíván, takže můžete předejít placení katastrofických částek.
![Ceny Codespaces](/assets/images/codespaces/1.jpg)
Je to určitě výhodnější, než si platit např. hotové VPS, pokud ho tedy nepoužíváte i na něco smysluplnějšího.
Moje zkušenost
Samozřejmě jsem nemohl odolat a na OpenCanteen jsem si jeden nechal vytvořit, aniž bych věděl do čeho se vrhám.
Codespace se vytváří jednoduše kliknutím na tlačítko "Code" ve vašem repozitáří, kde se vám nově zobrazí možnost si Codespace vytvořit.
Ve výchozím stavu běží server na Ubuntu. Pokud nenajdete docker obraz nebo devcontainer konfigurační soubor, musíte si samozřejmě vše nainstalovat sami, což zas tolik nevadí, protože to nejspíš budete dělat jen jednou, pokud si nebudete s obrazem stroje nějak zahrávat.
Instalace všeho však probíhá svižně, jelikož asi v Microsoftu mají na rychlejší internet, než já. Samozřejmě vše musíte instalovat skrze terminál (což mě celkem ranilo, jelikož instalovat Android SDK pro flutter byla celkem fuška).
Pokud používáte Settings Sync ve VS Code, automaticky se vám synchronizují nastavení a rozšíření. Pro pokročilé upravení prostředí slouží konfigurační soubor devcontainer.json
![Ceny Codespaces](/assets/images/codespaces/2.jpg)
Jakmile máte všechno nastavené, už stačí jen využít starého známého Visual Studio Code, které funguje úplně stejně jako na lokálním zařízení. Na Codespace se můžete kdykoli připojit přes webovou adresu.
Za mě velice praktické pro dříve uvedené typy lidí, už jen záleží, jestli se to zrovna vám za ty peníze vyplatí. Dokumentace je možná trochu chaotická, alespoň pro uživatele co se nevyznají v technologiích jako kontejnery či docker a většiny funkcí využije jen skutečný poweruser (což já určitě nejsem).

View file

@ -1,126 +0,0 @@
---
layout: post
title: NordVPN - Jste opravdu v takovém nebezpečí?
subtitle: Ale je to špatná služba?
categories: bezpečí
tags: vpn youtube reklamy
sidebar: []
---
Pokud sledujete YouTube, určite jste už narazili na nespočet videí, které sponzoruje nějaký poskytovatel tzv. **VPN**. Většinou se dozvíte něco jako „vaše data jsou v nebezpečí“ a/nebo „použijte naše služby pro zabezpečení vašich dat před hackery“. Toto se samozřejmě netýká *jen* NordVPN, ale myslím, že ti mají tu nejagresivnější marketingovou strategii snad ze všech.
# ČÁST I: Kecy
## Kdo stojí za NordVPN
NordVPN vzniklo v roce 2012 jako produkt Toma Okmana, Eimantase Sabaliauskase a Jonase Karklyse. Služba má sloužit jako tzv. __Virtual Private Network__ neboli virtuální soukromá síť. Můžete se tak skrze NordVPN servery připojovat na internet třeba z Německa. Dle zvoleného protokolu je síťový provoz šifrován. NordVPN vlastní společnost [Nord Security](https://nordsecurity.com/), která zastřešuje i ostatní produkty značky Nord. Sídlo má ve Velké Británii. Nord Security kromě VPN nabízí i vlastního správce hesel a šifrovaný cloud.
## NordVPN a reklamy YouTuberů
Reklamy uvnitř obsahu, tedy reklamy, které tvůrce přidává přímo do videa výměnou za přímou platbu od společnosti, jsou tu s námi celkem dlouho. Jsou **efektivnější** než běžné reklamy, protože je s běžným blokovačem reklam nepřeskočíte a často je tvůrci tvoří zábavným způsobem, aby je sledující sám nepřeskočil. Je to **stabilnější příjem** pro tvůrce obsahu, jelikož se nemusí spoléhat na výdělek z reklam, které YouTube často omezuje svými pravidli demonetizace. To je také jeden z důvodů, proč často youtubeři těmto druhům reklam vyjdou vstříc, i když nemusí mít o daném produktu žádnou znalost. Často tak ve svých videích poskytují nepravdivé či přímo zavádějící tvrzení. Než uvedu příklady, je nutné si uvědomit, že **ne každý takový YouTuber poskytuje zavádějící informace** nebo že **NordVPN nejsou žádní podvodníci**. Nejsem žádný „samozvaný IT expert“, takže mě neváhejte případně opravit. A o tvrzení „NordVPN je nejlepší VPN“ se bavit ani nebudu, o tom si udělejte obrázek sami.
### Tvrzení č. 1:
**[Veřejné WiFi jsou nebezpečné a kdokoliv může sledovat, co na nich děláte](https://youtu.be/51TNTCAD8fQ?t=68)**
Zalíbila se mi [odpověď Scotta Helmse](https://www.quora.com/Is-it-safe-to-use-internet-from-open-public-WiFi-hotspots/answer/Scott-Helms-8), který přirovnává veřejné WiFi sítě k veřejným ulicím. Pokud budete dělat hlouposti, jako je chození s přilepenou platební kartou na čele, samozřejmě vaše údaje budou odcizeny. Proto určitě není dobrý nápad dělat nákupy či se přihlašovat do bankovnictví skrz veřejné sítě. Když se na to podíváme realisticky, je relativně malá šance, že si zrovna k vám v mekáči sedl chlapec či dívka s laptopem, na kterém projíždí vaši historii vyhledávání. Navíc většina webů je zabezpečená pomocí SSL, takže přenos dat je šifrovaný. Takže při používání VPN to vlastně šifrujete ještě jednou (?), což už ale tak užitečné není. Jak [píše](https://www.eff.org/deeplinks/2020/01/why-public-wi-fi-lot-safer-you-think) EFF, tyto hrozby jsou díky HTTPS/SSL spíše minulostí. Váš poskytovatel internetu může sledovat např. jakou stránku otevíráte (třeba github.com), nicméně neuvidí žádné parametry, které odesíláte, ani jestli navštěvujete github.com/hernikplays nebo github.com/ytdl. A to stejné mohou lidé, kteří jsou kolem vás připojení na veřejné WiFi. „V životě se bojíte spousty věcí, veřejné WiFi si můžete ze seznamu odškrtnout“.
### Tvrzení č. 2:
**[[NordVPN poskytuje] maximální internetové bezpečí](https://youtu.be/a_LiGXtXXNQ?t=1642)**
Jak už jsem řekl v předchozí části, před vlastní blbostí vás ani to nejlepší VPN nezachrání. Pokud máte selský rozum, tak poznáte, kam zadávat a nezadávat svoje osobní údaje, což se s rostoucí popularitou sociálního inženýrství o něco zhoršuje. A pokud si vás přecijen nějaký špičkový, státem placený hacker najde, tak mu VPN určitě nebude dělat problém.
### Tvrzení č. 3:
**[Zatímco [bez VPN] ti může jakýkoliv útočník vcelku jednoduše tvé zařízení nabourat, s ním jsi prakticky neviditelný […] smaže za tebou tvou stopu](https://youtu.be/sB8vHDS1Tcg?t=380)**
Toto tvrzení je možná pravdivé pro NordVPN, jelikož nabízejí službu „[Threat Protection](https://nordvpn.com/features/threat-protection/)“, která slouží k blokování reklam, sledovacích prvků a nebezpečných webů, nicméně může vzbudit dojem, že takhle operuje každé VPN. Pokud vám jde o vaše bezpečí, neměli byste sázet na řešení jedním kliknutím, ale [prozkoumat různé možnosti a nástroje](https://mullvad.net/en/help/first-steps-towards-online-privacy/), včetně VPN. Pokud používáte např. služby od Googlu, už tak jim o sobě poskytujete dostatek údajů.
Útočník také nemůže „vcelku jednoduše“ vaše zařízení nabourat, to lze pouze pokud jste se rozhodli používat Windows 10 a nenainstalovali jste žádné aktualizace. V tom případě je váš systém děravý jak ementál a to už asi nikdo, kromě vás, nespraví. Takže aktualizujte svůj systém a aplikace jak to jen půjde!
### Tvrzení č. 4:
**Můžeš sledovat obsah uzamknutý pro určité země**
To je samozřejmě pravda, nicméně některé služby se aktivně pokouší zamezit přístup uživatelům s VPN identifikováním IP adresy daného VPN serveru.
### Tvrzení č. 5:
**[[NordVPN] ti zrychlí internet](https://youtu.be/sB8vHDS1Tcg?t=436)**
Když máte od poskytovatele internetu omezené stahování na 10 MB/s, nemůžete očekávat, že když budete ze serveru, kde může být zároveň napojeno X tisíc lidí a je někde v tramtárii, stahovat soubor, že se bude stahovat rychleji. [Pouze ve specifických případech](https://www.cloudflare.com/learning/access-management/vpn-speed/), kdy například poskytovatel internetu záměrně zpomaluje připojení např. k Netflixu, můžete pocítit zrychlení.
## NordVPN a ještě divnější praktiky
Zavádějícími tvrzeními to však nekončí, věděli jste, že na mnoha webech s hodnoceními VPN služeb si můžete určitou pozici **jednoduše koupit**? Ano, dostáváme se do takzvaného **provizního systému**, tedy systému, ve kterém firma proplatí provizi z provedeného nákupu jistému zprostředkovateli. Vtipná věc je, že některé tyto firmy [vlastní](https://blog.windscribe.com/consolidation-of-the-vpn-industry-spells-trouble-for-the-consumer-57e638634cf0/) zároveň takovéto *„publikace“* a samotné VPN služby, jako např. Kape Technologies, která se původně **zabývala adwarem**, nyní vlastní např. ExpressVPN a zároveň web VPNmentor. NordVPN není výjimkou s jejich provizním systémem nabízejícím až 40% část z ceny nákupu. Dá se těmto „hodnocením“ vůbec věřit? Některým nejspíš ano, je dobré však zkontrolovat, jestli publikaci nevlastní nějaká mediální společnost.
Dále můžeme na webu NordVPN, služby, která vám má pomoct chránit vaše soukromí a *„zneviditelnit se“*, **najít spoustu sledovacích prvků**, jako např. sledovací prvky Twitter Ads, Google Ads, Analytics a Bing.
![Ukázka sledovacích prvků na stránce NordVPN](/assets/images/vpn/14.png)
# Část II: Vzhůru dolů
Ano, je čas, abych se vydal do králičí nory a NordVPN otestoval. Hned na úvodní stránce na vás vyskočí tuny slev. „Nakupte do X hodin a získejte slevu X%“. No tak to abych si pohnul, co? Samozřejmě, že ne. Úplně stejná stránka s úplně stejným odpočtem se mi zobrazila i včera. Navíc tato sleva platí jen na roční plány a já s NordVPN chci strávit co nejméně času. Takže beru jejich standardních 10,49 eur na měsíc, které naštěstí také nabízejí s garancí vrácení peněz. Samozřejmě k tomu ještě musíte přičíst daně, z čehož máme 12,69 *(nice)*. Použil jsem jejich [(ne)](https://www.theregister.com/2020/03/06/nordvpn_no_auth_needed_view_user_payments/)bezpečnou bránu a vzdal se svých těžce vydělaných peněz.
Jejich stránka, ze které jsem měl stáhnout klienta, se chvástala „online zabezpečením pro všechny velké linuxové distribuce“, takže je super, že nabízejí stažení pouze pro distribuce založené na Debianu a RHEL, když jsem na Archu. Samozřejmě nic, co by Arch komunita nevyřešila.
Nemůžu hodnotit jednoduchost prostředí, protože *to na linuxu ani není*. Nicméně se podíváme na rychlost.
## Rychlosti (velmi stručně)
![Výchozí rychlost (bez VPN, WiFi)](/assets/images/vpn/13.png)
Výchozí rychlost (bez VPN, WiFi)
![NordVPN Germany #1078](/assets/images/vpn/12.png)
NordVPN Germany #1078
![Rychlost stahování torrentů na serverech v Německu](/assets/images/vpn/11.png)
Pokles rychlosti, úplně normální, protože pakety urazí větší vzdálenost. Streamování YouTube ve Full HD má pocititelné zpomalení/zasekávání. Rychlosti stahování torrentů se držely v průměru mezi 600 a 700 KB/s.
![NordVPN USA #9363](/assets/images/vpn/10.png)
NordVPN USA #9363
![Rychlost stahování torrentů na serverech v USA](/assets/images/vpn/9.png)
Tady už změnu pocítíte víc. Zajímavé však je, že se videa z YouTube ve Full HD načítají rychleji. Nicméně rychlosti stahování torrentů skákaly nahorů a dolů.
## Threat Protection Lite
Další funkce dostupná pro linux je [TPL](https://support.nordvpn.com/General-info/Features/1047407402/What-are-Threat-Protection-and-Threat-Protection-Lite.htm), který má blokovat reklamy, nebezpečné stránky a pochybná připojení během připojení na VPN.
Na webu NordVPN zablokoval sledovací prvky Twitteru, Bingu a Googlu, nicméně vynechal Google Analytics (což je asi pochopitelné, když o blokování sledujících prvků není ani zmínka).
![Zablokované sledovací prvky na NordVPN.com](/assets/images/vpn/8.png)
Na YouTube neblokuje reklamy vůbec,
![Blokování reklam s TPL na YouTube](/assets/images/vpn/7.png)
ale na jiných webech ano.
![Blokování reklam s TPL na jiných webech](/assets/images/vpn/6.png)
Takže nahradí blokovače jako [uBlock Origin](https://github.com/gorhill/uBlock#readme)? Řekl bych, že ne.
# Část III: Opouštíme králičí noru
Dobře, mám trochu NordVPN na vlastní kůži, ale teď se ho chci zbavit. Takže jdeme žádat zpět peníze.
Zrušení obnovení předplatného bylo relativně snadné, v nastavení účtu stačilo kliknout na „Zrušit“.
![Zrušení obnovení předplatného](/assets/images/vpn/5.png)
Teď přijde ta bolestivější část, a to žádání o vrácení peněz. Dle podmínek máte 30 dní od prvního nákupu nárok na vrácení peněz.
NordVPN říká, že podpora funguje 24/7. Na začátku jste spojeni s robotem, který vás postupně přepojí na živého člověka.
![Robot na podpoře](/assets/images/vpn/4.png)
Člověk se skutečně objevil.
![Chat s podporu část 1](/assets/images/vpn/3.png)
Chvilku mu to trvalo, takže jsem ho popostrčil.
![Chat s podporu část 2](/assets/images/vpn/2.png)
Řekl jsem mu slušně „Ne, díky“, po čemž mi nastavil vrácení peněz.
![Chat s podporu část 3](/assets/images/vpn/1.png)
Celkem rychle vyřízeno, dobrá práce. Zvláštní mi přišlo jen, že si mě nijak neověřil, pouze jsem na začátku poskytl e-mail, z čehož (doufám) vydedukoval, že to patří k mému účtu.
Další den mi skutečně odebrali přístup k jejich službě, nicméně peníze jsou stále zablokované, tak snad si banka pohne.
# Část V: Závěr
Takže na závěr:
**Je VPN úplně zbytečný nástroj?** Určitě ne.
**Můžou youtubeři za to, že někdy neříkají pravdivé věci?** Spíš ne, nemůžete čekat každého youtubera, že je expert přes sítě, jenom se snaží se uživit a vyloženě lži říkají opravdu málokdy.
**Snaží se NordVPN prodat hadí olej a moje děti na darknetu?** Nejspíš ne, ale měli by víc sjednotit prezentování co se týče sponzorování youtuberů.
**Můžu důvěřovat NordVPN?** S jejich velikostí nejspíš ano.
**Doporučil bych NordVPN?** Ne. Pokud chcete opravdu 100% anonymitu a hlavně no-bullshit produkt, použijte něco jako Mullvad *(toto není sponzorováno, sám ho používám a je fajn)*, který nenabízí žádné posrané slevy kvůli všemu možnému a kde dokonce můžete platit v hotovosti, ale nezapomeňte, že VPNkem to nekončí. Podívejte se na [Surveillance Self-Defense](https://ssd.eff.org/) od EFF pro více tipů na ochranu vašeho soukromí.

View file

@ -1,102 +0,0 @@
---
layout: post
title: Instalujeme Arch Linux ARM na Raspberry Pi 3
subtitle: Protože proč ne
categories: tutoriál
tags: návod rpi arch
sidebar: []
---
![Arch Linux ARM logo](https://archlinuxarm.org/public/images/alarm.png)
Raspbian OS už je ohraný. Pojďme si nainstalovat [ARM verzi Arch Linuxu](https://archlinuxarm.org/platforms/armv8/broadcom/raspberry-pi-3) na Raspberry Pi 3. Proces je relativně prostý.
# Připravujeme SD kartu
Nejdřív je nutné SD kartu naformátovat a rozdělit oddíly. Můžete to udělat svým oblíbeným způsobem, já použiji GUI nástroj GParted.
Odstraníme všechny oddíly skrz kontextové menu pravého kliknutí a potvrzení fajfkou.
![Odstraněné oddíly v GParted](/assets/images/rpi-arch/01.png)
Následně vytvoříme jeden FAT32 oddíl, který bude sloužit jako bootovací. Bude stačit 128 MiB.
![Vytváření FAT32 oddílu v GParted](/assets/images/rpi-arch/02.png)
Druhý oddíl bude náš systémový, který bude ext4.
![Vytváření ext4 oddílu v GParted](/assets/images/rpi-arch/03.png)
Jakmile fajfkou potvrdíme a necháme oddíly vytvořit, můžete je ještě zformátovat, nicméně je nejdůležitější nastavit `boot` příznak na našem boot oddílu skrz kontextové menu.
![Výběr příznaků v GParted](/assets/images/rpi-arch/04.png)
Tak je všechno hotovo v GParted.
# Přesouváme systém
Dále připojíme naše oddíly podle jejich identifikátoru a čísla připojíme.
Nejdřív si vytvoříme složky, `sudo mkdir -p /mnt/archpi/{root,boot}` nám vytvoří složky `root` a `boot` pro naše oddíly.
Dále příkazem `sudo mount /dev/sdc1 /mnt/archpi/root` připojíme náš FAT32 bootovácí oddíl (**Označení `sdc1` se u vás může lišit, podívejte se do GPartedu nebo skrz příkaz `lsblk` na označení jednotlivých oddílů**) a příkazem `sudo mount /dev/sdc2 /mnt/archpi/boot` připojíme systémový oddíl.
Dle oficiální [dokumentace](https://archlinuxarm.org/platforms/armv8/broadcom/raspberry-pi-3) se další proces má dělat skrz root uživatele, takže se přepneme příkazem `sudo su`.
Příkazem `wget http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-armv7-latest.tar.gz` stáhneme archiv a příkazem `tar -xf ArchLinuxARM-rpi-armv7-latest.tar.gz -C /mnt/archpi/root` ho rozbalíme.
Pak musíme přesunout bootovací soubory do bootovacího oddílu: `mv /mnt/archpi/root/boot/* boot` a tím jsme hotovi, stačí oddíly odpojit příkazem `umount /mnt/archpi/root` a `umount /mnt/archpi/boot`. Jakmile se příkazy dokončí, můžete SD kartu vložit do RPi a zapnout.
Výchozí jméno a zároveň heslo uživatele je `alarm` a roota `root`. Než bude systém nastavený, doporučuji použít `root` účet.
# Připojení k Wi-Fi síti
*Pokud používáte kabelové připojení, tak můžete přeskočit*
Nyní se připojíme skrz terminál k Wi-Fi síti. Předpokládám, že název (SSID) sítě a heslo znáte a že zabezpečení je WPA2 Personal. Jinak si můžete prohlédnout [Arch Wiki](https://wiki.archlinux.org/title/Network_configuration/Wireless) pro více návodů.
Příkazem `iw dev` zjistíte název vašeho interfacu (např. já mám `wlan0`). Zapneme ho pomocí `ip link wlan0 up` (místo `wlan0` tedy použijte váš název interfacu).
Dále se tedy připojíme k nějaké Wi-Fi síti. Nejdřív musíme vytvořit konfigurační soubor pro `wpa_supplicant`, který slouží jako [suplikant](https://cs.wikipedia.org/wiki/Suplikant) s podporou WPA, WPA2 a WPA3.
Pomocí příkazu `nano /etc/wpa_supplicant/wpa_supplicant.conf` vstoupíme do editace konfiguračního souboru. Do něj vložíme následující dva řádky:
```
ctrl_interface=/run/wpa_supplicant
update_config=1
```
Klávesovou zkratkou `Ctrl+X`, zadáním `y` a potvrzením enterem uložíme soubor a opustíme editaci. wpa_supplicant teď můžeme spustit příkazem `wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf`.
S běžícím wpa_supplicant můžeme použít příkaz `wpa_cli`, kde můžeme konfigurovat síť.
Sítě zde můžete hledat příkazem [`scan`](https://wiki.archlinux.org/title/Wpa_supplicant#Connecting_with_wpa_cli), následováný `scan_results`.
Pro přidání sítě použijeme příkaz `add_network`. Terminál vrátí `0`, což je ID sítě, které můžeme konfigurovat. Příkazem `set_network 0 ssid "MYSSID"` nastavíme SSID (název) sítě na `MYSSID`. Příkazem `set_network 0 psk "passphrase"` nastavíme heslo na `passphrase`. Jakmile je nastaveno, můžeme povolit síť pomocí `enable_network 0`. Konfiguraci uložíme příkazem `save_config` a opustíme pomocí `quit`.
Jelikož ale právě teď nemáme IP adresu, musíme nastavit službu DHCP (pokud ji samozřejmě váš router má). Stačí zapnout službu `dhcpcd` pomocí příkazu `systemctl enable dhcpcd`. Abychom při každém zapnutí nemuseli síť manuálně zapínat, můžeme do `dhcpcd` přidat [hook](https://wiki.archlinux.org/title/Dhcpcd#10-wpa_supplicant), který ji automaticky zapne, stačí použít `ln -s /usr/share/dhcpcd/hooks/10-wpa_supplicant /usr/lib/dhcpcd/dhcpcd-hooks/`.
V tomto stádiu doporučuji restartovat příkazem `reboot`.
# Nastavujeme správce balíků
Aktuálně bychom měli mít funkční síť, nicméně je potřeba pár dalších příkazů pokud chceme používat `pacman` správce balíků.
Nejdřív musíme vytvořit klíčenku příkazem `pacman-key --init`, poté přidáme klíče Arch ARM repozitářů příkazem `pacman-key --populate archlinuxarm`. Teď můžete příkazem `pacman -Sy` repozitáře synchronizovat.
Jako první balík bychom měli stáhnout [`sudo`](https://wiki.archlinux.org/title/sudo), abychom nemuseli používat `root` uživatele pro všechno nastavování. Nainstalujeme ho příkazem `pacman -S sudo`. Dále příkazem `nano /etc/sudoers` upravíme konfiguraci. Najdeme následující řádky (`Ctrl+W` pro hledání):
```
## Uncomment to allow members of group wheel to execute any command
#%wheel ALL=(ALL:ALL) ALL
```
a odstraníme mřížku před `%` pro odstranění komentáře. Tím umožníme uživatelům v uživatelské skupině `wheel` používat příkaz `sudo`.
Nyní přidáme uživatele `alarm` do skupiny `wheel` příkazem `gpasswd -a alarm wheel`. A teď už můžeme používat uživatele `alarm` pro různé administrativní operace místo roota.
# Nastavení SSH přístupu
Možná vás nebaví zapojovat RPi do monitoru nebo u něj klapat věci do klávesnice v terminálu nebo jen chcete vzdálený přístup. SSH lze povolit skrz OpenSSH, které je na Archu předinstalované. Stačí povolit službu pomocí `systemctl enable sshd`. Pro nějakou pokročilou konfiguraci si prohlédněte [Arch Wiki](https://wiki.archlinux.org/title/OpenSSH#Server_usage).
Nyní se stačí připojit skrz nějaký SSH klient na vaše zařízení (pokud neznáte IP, podívejte se skrz příkaz `ip a`), třeba skrz `ssh alarm@vase.ip.adresa`.
# HTTPS problémy
Pokud máte problémy s SSL nebo komunikací se zabezpečenými servery, zkuste nainstalovat balík `ca-certificates` a nastavit systémový čas skrz `timedatectl set-time "2022-10-29 15:00:00` (samozřejmě vaše datum).
# Závěr
![Arch neofetch](/assets/images/rpi-arch/05.png)
Instalace je opravdu prostý a snadný proces (i když jsem ho sám dělal asi 5x než mi to nabootovalo), takže určitě zkoušejte a zkoušejte.

View file

@ -1,102 +0,0 @@
---
layout: post
title: Jak si vytvořit přenosný Arch Linux systém na USB
subtitle: Protože občas je Linux nutný na cestách
categories: tutoriál
tags: návod arch
sidebar: []
---
# Co bude potřeba
- Systém s Linuxem
- USB s alespoň 4 GB místa
{: .box-note}
**Poznámka:** Instalaci můžete provést i na Windows či macOS, stačí si nainstalovat VirtualBox, na kterém spustíte nějaký linux systém skrz live ISO a následně řeknete VirtualBoxu, aby přesměroval vaše přenosné USB do virtuálního počítače.
# 1. Příprava USB
{: .box-note}
**Poznámka:** Pokud instalujete systém, který má GUI instalátor, můžete nejdřív zkusit systém nainstalovat přes něj.
## 1.1 Rozdělení na oddíly
Pro jednoduchost budu používat nástroj GParted, který je dostupný snad na všech distribucích. Skrz něj si na USB v záložce `Zařízení` vytvoříme novou tabulku oddílů. Jako typ zvolíme `gpt` a dáme `Použít`.
Dále si vytvoříme naše systémové oddíly. Pokud používáte UEFI (což dnes asi ano), vytvoříme na disku oddíl ve formátu FAT32 o velikosti ~500 MiB (to je [**MiB**](https://simple.wikipedia.org/wiki/Mebibyte), **nikoli MB**; pokud plánujete používat více jader tak třeba 800 MiB). Ten bude sloužit jako [EFI systémový oddílový](https://wiki.archlinux.org/title/EFI_system_partition). Ze zbytku vytvoříme nový EXT4 oddíl, na kterém bude náš systém.
Naše rozdělení pak bude vypadat asi takto:
![GParted zobrazení oddílů na USB](/assets/images/portable-arch/01.png)
Nyní je třeba naše oddíly připojit k našemu již běžícímu systému.
## 1.2 Připojení
Nejdřív si zjistíme označení našich oddílů. Na to stačí příkaz `lsblk`.
![Výpis lsblk](/assets/images/portable-arch/02.png)
V mém případě je USB označeno jako `sdb`, kde EFI oddíl je `sdb1` a sýstemový oddíl je `sdb2`.
V `/mnt` si vytvoříme složku, kam naše oddíly připojíme. Nejdřív připojíme náš systémový oddíl.
```sh
sudo mount --mkdir /dev/sdb2 /mnt/usb
```
Poté vytvoříme složku v `/mnt/usb`, do které připojíme náš EFI oddíl. Složka by se měla jmenovat vždy `boot`.
```sh
sudo mount --mkdir /dev/sdb1 /mnt/usb/boot
```
# 2. Instalace Arch Linuxu
## 2.1 Instalace nutných balíků
Přípravu systému provedeme příkazem `pacstrap`, který je dostupný v balíku `arch-install-scripts`. Příkaz nám nainstaluje základní balíky a linuxové jádro.
```sh
pacstrap -K /mnt/usb base linux linux-firmware coreutils bash grep gawk file tar gzip systemd sed sudo nano
```
Pokud chcete použít jiné jádro, stačí nahradit `linux` za jádro vašeho výběru.
## 2.2 Nastavení GRUB
GRUB nám bude sloužit k nabootování. Instalovat ho budeme už přímo na náš přenosný systém, takže se v našem nepřenosném systému přeneseme do jeho prostředí pomocí príkazu `arch-chroot` (součástí `arch-install-scripts`).
{: .box-note}
**Poznámka:** Pokud jste nenásledovali UEFI instrukce, bude se tento krok lišit, vizte [Arch Wiki návod](https://wiki.archlinux.org/title/GRUB#BIOS_systems)
```sh
sudo arch-chroot /mnt/usb/
```
Nejdříve nainstalujeme balíky `grub` a `efibootmgr` příkazem `pacman -S grub efibootmgr`. Jelikož není úplně ideální používat Secure Boot s linuxem a nastavovat ho je celkem otrava, bude v tomto návodu přeskočen. Budete-li ho potřebovat, následujte [oficiální Arch Wiki návod](https://wiki.archlinux.org/title/GRUB#Secure_Boot_support).
Nasměrujeme GRUB instalaci na náš EFI oddíl. Protože jsme uvnitř našeho přenosného systému, nesměrujeme na `/mnt/usb` ale přímo `/` (v případě nejistoty zkontrolujte lokaci EFI oddílu příkazem `lsblk`).
```sh
grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB --removable
```
Po instalaci ještě musíme vytvořit základní konfigurační soubor.
```sh
grub-mkconfig -o /boot/grub/grub.cfg
```
## 2.3 Vytvoření prvního uživatele
Uživatele přidáme příkazem `useradd`. Pro vytvoření uživatele s domovskou složkou použijeme `useradd -m jmenouzivatele`. Pro vytvoření hesla použijeme příkaz `passwd`: `passwd jmenouzivatele`.
Uživatele rovnou přidáme do skupiny sudařů, abychom nemuseli používat roota na administrátorské procesy. Nejdříve ale musíme umožnit skupině, aby příkaz `sudo` mohla používat. Otevřeme si konfiguraci příkazem `visudo` a kombinací `Ctrl+W` vyhledáme `%sudo`. Sekce by měla v souboru vypadat takto:
```
## Uncomment to allow members of group sudo to execute any command
# %sudo ALL=(ALL:ALL) ALL
```
Odstraníme mřížku před `%` a soubor uložíme stisknutím kombinace `Ctrl+X`, poté klávesy `y` a `enter`. Teď stačí skupinu vytvořit příkazem `groupadd sudo` a uživatele přidat do skupiny příkazem `usermod -aG sudo jmenouzivatele`.
## 2.4 Nainstalujte, co je třeba
Nejlépe následujte návod na [Arch Wiki](https://wiki.archlinux.org/title/Installation_guide#Time_zone) pro doinstalování všeho, co je potřeba pro funkční systém.
## 3. Konec
Nyní stačí jen nabootovat a nainstalovat vše co jen potřebujete.
Adaptováno z [Install Arch Linux on a removable medium](https://wiki.archlinux.org/title/Install_Arch_Linux_on_a_removable_medium) od autorů Arch Wiki pod licencí [CC-BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/)

View file

@ -1,62 +0,0 @@
/*
* Post menu
*/
.post-menu {
padding-left: 20px;
min-width: 200px;
max-width: 230px;
.post-menu-title {
font-size: $base-font-size * 1.5;
margin-bottom: 14px;
font-weight: 600;
color: #222;
}
.post-menu-content {
ul {
border-left: 1px solid #e9ecef;
$indent: $base-font-size / 4;
$active-bgcolor: #ecebec;
@for $i from 2 to 7 {
.h-h#{$i} {
padding-inline-start: $indent + ($i - 2) * $base-font-size * 1.3;
font-size: $base-font-size * 1.1;
line-height: 1.4;
}
}
a {
display: flex;
padding: 2px 8px;
color: darken($text-color, 10%);
* {
pointer-events: none;
}
&:hover {
text-decoration: none;
color: lighten($text-color, 20%)!important;
}
}
.active {
background-color: $active-bgcolor;
transition: background 0.5s;
border-left: 2px solid #202020;
margin-left: -2px;
&:hover {
background-color: lighten($active-bgcolor, 2%);
}
a {
color: #121416;
}
}
}
}
}

View file

@ -1,46 +0,0 @@
.click-to-top {
transition: 0.3s;
display: flex;
align-items: center;
justify-content: center;
position: fixed;
width: 64px;
height: 64px;
border-radius: 32px;
right: 60px;
bottom: 48px;
background: white;
cursor: pointer;
opacity: 0;
transform: translateY(10px);
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.15);
font-size: 24px;
user-select: none;
@include media-query(1024px) {
width: 48px;
height: 48px;
border-radius: 24px;
right: 35px;
font-size: 20px;
}
@include media-query($on-palm) {
width: 36px;
height: 36px;
border-radius: 18px;
right: 20px;
font-size: 16px;
}
}
.click-to-top.show {
opacity: 1;
transform: translateY(0);
}
html[data-theme="dark"] {
.click-to-top {
background: #34323D;
}
}

View file

@ -1,45 +0,0 @@
/**
* Common list
*/
.common-list {
@include relative-font-size(1.0);
min-width: 200px;
ul {
list-style: none;
margin: 0;
}
li {
border-bottom: solid 1px #00000018;
&:last-child {
border-bottom: none;
}
a {
display: flex;
justify-content: space-between;
padding: 8px 12px;
text-decoration: none;
font-weight: normal;
color: $text-color;
transition: background 0.2s;
&:hover {
background-color: mix($theme-color, #eaeaea, 20%);
}
}
span {
@include relative-font-size(0.8);
display: inline-block;
border-radius: 10px;
align-self: center;
background: #000000bd;
padding: 0px 8px;
margin-left: 20px;
color: $white-color;
}
}
}

View file

@ -1,16 +0,0 @@
.gitment-container {
color: #787878 !important;
}
.gitment-editor-header {
background-color: #fefefe;
}
.gitment-comment-main, .gitment-editor-main {
background-color: #fff;
border-radius: 3px !important;
}
.gitment-heart-icon {
fill: #ff0808;
}

View file

@ -1,196 +0,0 @@
/* OVERRIDE GOOGLE TRANSLATE WIDGET CSS BEGIN */
%goog-te-menu {
a.goog-te-menu-value {
vertical-align: top !important;
&:hover {
text-decoration: none;
}
span {
color: #aaa;
}
span:hover {
color: white;
}
/* Remove the down arrow */
/* when dropdown open */
span[style="color: rgb(213, 213, 213);"] {
display: none;
}
/* after clicked/touched */
span[style="color: rgb(118, 118, 118);"] {
display: none;
}
/* on page load (not yet touched or clicked) */
span[style="color: rgb(155, 155, 155);"] {
display: none;
}
/* Remove span with left border line | (next to the arrow) in Chrome & Firefox */
span[style="border-left: 1px solid rgb(187, 187, 187);"] {
display: none;
}
/* Remove span with left border line | (next to the arrow) in Edge & IE11 */
span[style="border-left-color: rgb(187, 187, 187); border-left-width: 1px; border-left-style: solid;"] {
display: none;
}
}
}
div#google_translate_element {
display: inline;
div.goog-te-gadget {
display: inline;
font-size: 0;
}
div[id=':0.targetLanguage'] {
display: inline;
}
div.goog-te-gadget-simple {
border: none;
background-color: transparent;
@extend %goog-te-menu;
}
a.goog-logo-link {
display: none;
}
.goog-te-gadget-icon {
display: none !important;
/*background: url("url for the icon") 0 0 no-repeat !important;*/
}
a.goog-te-menu-value {
margin: 0;
span:first-child {
display: none;
}
&:before {
content: "\f1ab \f0d7";
font-family: FontAwesome;
font-size: initial;
color: #fefefe;
border: 1px solid #fefefe85;
border-radius: 3px;
padding: 3px 6px;
}
}
}
.goog-te-menu-frame .goog-te-menu2 {
max-width: 100%;
overflow-x: auto;
box-sizing: border-box;
height: auto;
}
/* HIDE the google translate toolbar */
.goog-te-banner-frame.skiptranslate {
display: none !important;
border: none;
box-shadow: 0 0;
-webkit-box-shadow: 0 0;
}
body {
top: 0px !important;
}
/* OVERRIDE GOOGLE TRANSLATE WIDGET CSS END */
// Main look
.ct-language-selected {
background-color: darken($theme-color, 5%) !important;
}
.ct-language-dropdown {
overflow: hidden;
max-height: 0;
position: absolute;
top: 110%;
right: -10px;
background-color: lighten($theme-color, 5%);
-webkit-transition: all 0.25s ease-in-out;
transition: all 0.25s ease-in-out;
width: 100px;
text-align: center;
margin-top: 0;
z-index: 200;
border-radius: 3px;
visibility: hidden;
li {
padding: 5px;
&:first-child {
padding-top: 12px;
}
&:last-child {
padding-bottom: 12px;
}
&:not(:last-child) {
border-bottom: 1px solid rgba(0, 0, 0, .04);
}
a {
display: block;
color: invert($theme-color);
img {
width: 24px;
max-height: 24px;
border: none;
}
}
&:hover {
@extend .ct-language-selected;
}
}
}
.list-unstyled {
display: inline-block;
list-style: none;
margin-left: 0;
}
.ct-language {
display: inline-block;
position: relative;
background-color: #fefefe2b;
padding: 3px 10px;
border-radius: 3px;
&:hover {
cursor: pointer;
.ct-language-dropdown {
margin-top: 8px;
max-height: 10000px;
visibility: visible;
box-shadow: 0 0 9px 3px rgba(0, 0, 0, .06);
}
}
&:before {
content: "\f1ab \f0d7";
font-family: FontAwesome;
}
}

View file

@ -1,79 +0,0 @@
.theme-toggle {
position: relative;
width: $base-font-size * 7.65;
margin-top: 10px;
margin-right: 60px;
margin-left: auto;
transition: .3s cubic-bezier(.4,.03,0,1);
label, .toggle {
border-radius: 100px;
}
label {
display: block;
background-color: rgba(120,120,120,.15);
cursor: pointer;
}
.toggle {
position: absolute;
width: 50%;
height: 100%;
background-color: #fff;
box-shadow: 0 2px 15px rgba(0,0,0,.15);
transition: transform .2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.names {
font-size: 1em;
font-weight: bolder;
width: 76%;
margin-left: 12%;
position: relative;
display: flex;
justify-content: space-between;
user-select: none;
}
.dark {
opacity: .5;
}
p {
color: #acacac;
margin-bottom: 0;
line-height: 24px;
}
[type="checkbox"] {
display: none;
}
/* Toggle */
[type="checkbox"]:checked ~ label .toggle {
transform: translateX(100%);
background-color: #34323D;
}
[type="checkbox"]:checked ~ label .dark{
opacity: 1;
}
[type="checkbox"]:checked ~ label .light{
opacity: .5;
}
@include media-query(1024px) {
margin-right: 35px;
}
@include media-query($on-palm) {
width: $base-font-size * 6.65;
margin-right: 20px;
.names {
font-size: .85em;
}
}
}

View file

@ -1,70 +0,0 @@
@charset "utf-8";
// Define defaults for each variable.
$base-font-family: Helvetica, Arial, Oswald, sans-serif, !default;
$base-font-size: 14px !default;
$base-font-weight: 400 !default;
$small-font-size: $base-font-size * 0.875 !default;
$base-line-height: 1.6 !default;
$spacing-unit: 30px !default;
$text-color: #454545 !default;
$background-color: #fff !default;
$grey-color: #828282 !default;
$grey-color-light: lighten($grey-color, 40%) !default;
$grey-color-dark: darken($grey-color, 25%) !default;
$white-color: #fdfdfd !default;
$table-text-align: left !default;
$header-height: $base-line-height * $base-font-size * 2.85 !default;
$header-text-color: invert($theme-color) !default;
$header-background-color: $theme-color !default;
$footer-height: $header-height * 1.05 !default;
$footer-text-color: lighten(invert($theme-color), 25%) !default;
$footer-background-color: darken($theme-color, 5%) !default;
$banner-height: 640px !default;
$banner-text-color: lighten($white-color, 0%) !default;
$banner-background: rgba(0,0,0,0.8) !default;
// Width of the content area
// $content-width: 920px !default;
$on-palm: 600px !default;
$on-laptop: 800px !default;
// Use media queries like this:
// @include media-query($on-palm) {
// .wrapper {
// padding-right: $spacing-unit / 2;
// padding-left: $spacing-unit / 2;
// }
// }
@mixin media-query($device) {
@media screen and (max-width: $device) {
@content;
}
}
@mixin relative-font-size($ratio) {
font-size: $base-font-size * $ratio;
}
// Import partials.
@import
"yat/base",
"yat/layout",
"yat/dark",
"misc/theme-toggle",
"misc/article-menu",
"misc/common-list",
"misc/google-translate",
"misc/gitment",
"misc/click-to-top"
;

View file

@ -1,292 +0,0 @@
/**
* Reset some basic elements
*/
body, h1, h2, h3, h4, h5, h6,
p, blockquote, pre, hr,
dl, dd, ol, ul, figure {
margin: 0;
padding: 0;
}
/**
* Basic styling
*/
body {
font-family: $base-font-family;
font-weight: $base-font-weight;
font-size: #{$base-font-size};
font-display: swap;
line-height: #{$base-line-height};
color: $text-color;
background-color: $background-color;
-webkit-text-size-adjust: 100%;
-webkit-font-feature-settings: "kern" 1;
-moz-font-feature-settings: "kern" 1;
-o-font-feature-settings: "kern" 1;
font-feature-settings: "kern" 1;
font-kerning: normal;
display: flex;
min-height: 100vh;
flex-direction: column;
}
/**
* Set `margin-bottom` to maintain vertical rhythm
*/
h1, h2, h3, h4, h5, h6,
p, blockquote, pre,
ul, ol, dl, figure,
%vertical-rhythm {
margin-bottom: $spacing-unit / 2;
}
/**
* `main` element
*/
main {
display: block; /* Default value of `display` of `main` element is 'inline' in IE 11. */
}
/**
* Images
*/
img {
max-width: 100%;
vertical-align: middle;
}
/**
* Figures
*/
figure > img {
display: block;
}
figcaption {
font-size: $small-font-size;
}
/**
* Lists
*/
ul, ol {
margin-left: $spacing-unit;
}
li {
> ul,
> ol {
margin-bottom: 0;
}
}
/**
* Headings
*/
h1, h2, h3, h4, h5, h6 {
font-weight: $base-font-weight * 1.5;
}
/**
* Links
*/
a {
color: $brand-color;
text-decoration: none;
&:hover {
text-decoration: underline;
}
.social-media-list &:hover {
text-decoration: none;
.username {
text-decoration: underline;
}
}
}
/**
* Blockquotes
*/
blockquote {
color: $grey-color;
border-left: 4px solid $grey-color-light;
padding-left: $spacing-unit / 2;
@include relative-font-size(1.125);
letter-spacing: -1px;
font-style: italic;
> :last-child {
margin-bottom: 0;
}
}
/**
* Code formatting
*/
pre,
code {
@include relative-font-size(0.9375);
color: $text-color;
}
*:not(pre) > code {
padding: 3px 6px;
border-radius: 3px;
background-color: #eee;
margin: 0 5px;
}
pre {
overflow-x: auto;
position: relative;
background-color: #f0f0f0;
> code {
display: inline-block;
padding: 20px!important;
background-color: transparent;
border: 0;
}
table, pre {
margin-bottom: 0;
.gutter, .code {
padding: 6px;
border: none;
}
}
}
/**
* Wrapper
*/
.wrapper {
max-width: $content-width;
margin: auto;
padding-right: $spacing-unit;
padding-left: $spacing-unit;
@extend %clearfix;
}
/**
* Clearfix
*/
%clearfix:after {
content: "";
display: table;
clear: both;
}
/**
* Tables
*/
table {
display: block;
margin-bottom: $spacing-unit;
width: 100%;
text-align: $table-text-align;
color: lighten($text-color, 5%);
border-collapse: collapse;
overflow: auto;
tr {
&:nth-child(even) {
background-color: lighten($grey-color-light, 6%);
}
}
th, td {
padding: ($spacing-unit / 3) ($spacing-unit / 2);
}
th {
background-color: lighten($grey-color-light, 3%);
border: 1px solid darken($grey-color-light, 4%);
border-bottom-color: darken($grey-color-light, 12%);
}
td {
border: 1px solid $grey-color-light;
}
}
/**
* Flex layout
*/
%flex {
display: flex;
}
%flex-1 {
flex: 1;
min-width: 0; /* <-- fix flexbox width with pre tags */
}
/**
* Flex sticky
*/
@mixin flex-sticky($top) {
position: sticky;
position: -moz-sticky; /* <-- fix sticky compatibility issue */
position: -ms-sticky;
position: -o-sticky;
position: -webkit-sticky;
align-self: flex-start; /* <-- fix the sticky not work issue */
transform: scale(0.9999); /* <-- fix the sticky x overflow issue */
top: $top;
}
/**
* Vertical center
*/
@mixin vertical-center($position) {
position: $position;
top: 50%;
transform: translateY(-50%);
}
/**
* Horizontal center
*/
@mixin horizontal-center($position) {
position: $position;
left: 50%;
transform: translateX(-50%);
}
/**
* Center background image
*/
@mixin center-image {
height: 100%;
max-width: 1000%;
background-size: cover;
background-position: center center;
overflow: hidden;
}

View file

@ -1,212 +0,0 @@
$dark-background-color: #0e0e0e !default;
$dark-text-color: #bbb !default;
html[data-theme="dark"] {
&[data-scroll-status='top'] {
header.site-header-transparent {
&.site-header {
@include media-query($on-laptop) {
.page-link {
color: #f8f8f8;
}
}
}
}
footer.site-footer {
.site-footer-inner {
border-top: solid 1px #2f2f2f !important;
transition: 0s;
}
}
}
body {
color: $dark-text-color;
background-color: $dark-background-color;
}
*:not(pre) > code {
color: $dark-text-color;
background-color: #454545;
}
blockquote {
border-left: 4px solid #484848;
}
table {
color: #9d9d9d;
th {
background-color: #050505;
}
tr:nth-child(even) {
background-color: #080808;
}
}
.site-header {
background-color: #090909;
.site-brand {
.site-brand-inner {
&, &:visited {
color: #f8f8f8;
}
}
}
.site-nav .page-link {
color: #f8f8f8;
}
.ct-language-dropdown {
color: #f8f8f8;
background-color: $dark-background-color;
box-shadow: 0 0 3px 1px #0000005b;
}
.ct-language-selected, .ct-language-dropdown li:hover {
background-color: #222 !important;
}
@include media-query($on-laptop) {
.menu-icon > svg {
fill: rgba($dark-text-color, 80%);
}
.site-nav input:checked ~ .trigger {
background-color: #090909;
}
}
}
.site-footer {
color: #fff;
background-color: #000;
}
.left-vsplit:before {
background-color: #9a9a9a;
}
.page-banner {
.page-banner-img {
& > *:first-child {
opacity: 0.718;
}
}
}
.pagination {
.post-link {
color: $dark-text-color;
}
.post-title {
a:visited:after {
background-color: $dark-background-color;
}
a:after {
color: $dark-background-color;
}
}
.post-list {
& > li:not(:last-child) {
border-bottom: 1px solid #545454;
}
}
.post-tags .post-tag:hover {
color: #d7d7d7;
}
}
.page-segments {
li {
a {
color: #ddd;
}
a:visited:after {
background-color: $dark-background-color;
}
a:after {
color: $dark-background-color;
}
}
}
.post .post-content {
img:not([raw]) {
background-color: #ffffff33;
}
}
.post-related {
& > *:first-child {
color: #d7d7d7;
}
a:visited:after {
background-color: $dark-background-color;
}
a:after {
color: $dark-background-color;
}
a:hover {
color: #aaa;
}
}
.common-list {
li {
border-bottom: solid 1px #40404088;
a {
color: #aaa;
}
a:hover {
background-color: #272727;
}
span {
background-color: #333;
}
}
}
.post-menu {
.post-menu-title {
color: #ddd;
}
.post-menu-content {
ul {
border-left: 1px solid #787878;
.active {
background-color: #2d2d2d;
border-left: 2px solid #aaa;
}
a {
color: $dark-text-color;
}
a:hover {
color: #fff !important;
}
}
}
}
}

View file

@ -1,778 +0,0 @@
/**
* Animation for transparent header
*/
html {
&[data-header-transparent] {
header.site-header {
position: fixed;
}
}
&[data-scroll-status='top'] {
header.site-header-transparent {
height: 0;
margin-top: 12px;
background-color: transparent;
transition: 0.1s height,background-color,box-shadow;
&.site-header {
.site-brand-inner, .page-link {
color: #fff;
transition: 0.1s color;
}
@include media-query($on-laptop) {
.page-link {
color: $header-text-color;
}
.menu-icon {
> svg {
fill: $white-color;
}
}
}
}
}
footer.site-footer {
color: unset;
background-color: transparent;
.site-footer-inner {
border-top: solid 1px #eee;
}
}
}
&[data-scroll-status='down'] {
header.site-header {
top: -$header-height;
}
.framework .sidebar {
top: 20px;
}
}
}
/**
* Site header
*/
.site-header {
background-color: $header-background-color;
height: $header-height;
width: 100%;
transition: height 0.2s, text-shadow 0.2s, top 0.2s;
box-shadow: 0 1px 0 0 rgba(0, 0, 0, .06);
// Positioning context for the mobile navigation icon
@include flex-sticky(0);
z-index: 1000;
& > .wrapper {
margin: 0 60px;
padding: 0;
max-width: 100%;
transition: 0.2s margin;
@include media-query(1024px) {
margin: 0 20px;
max-width: unset;
}
}
a {
text-decoration: none;
}
.site-header-inner {
position: relative;
}
}
.site-brand {
line-height: $header-height;
margin-right: 50px;
.site-brand-inner {
@include relative-font-size(1.125);
font-weight: $base-font-weight;
letter-spacing: -1px;
transition: 0.1s filter color;
&, &:visited {
color: $header-text-color;
}
.site-favicon {
display: inline-block;
height: $header-height / 1.5;
margin-right: 5px;
}
}
}
.site-nav {
@include relative-font-size(1.125);
line-height: $header-height;
position: absolute;
right: 0;
top: 0;
.nav-trigger {
display: none;
}
.menu-icon {
display: none;
}
.page-link {
line-height: $base-line-height;
color: $header-text-color;
transition: 0.1s ease-in-out;
// Gaps between nav items, but not on the last one
&:not(:last-child) {
margin-right: 24px;
&:hover {
text-decoration: underline;
}
}
}
@include media-query($on-laptop) {
position: absolute;
top: 0;
text-align: left;
label[for="nav-trigger"] {
display: block;
z-index: 2;
cursor: pointer;
}
.menu-icon {
display: block;
float: right;
text-align: center;
> svg {
fill: rgba($header-text-color, 80%);
transition: 0.1s fill;
}
}
input ~ .trigger {
clear: both;
display: none;
border-radius: 3px;
box-shadow: 1px 1px 1px 1px rgba(0, 0, 0, .06);
}
input:checked ~ .trigger {
display: block;
background: $header-background-color;
}
.page-link {
display: block;
padding: 5px 10px;
color: rgba($header-text-color, 80%);
margin: 0 25px;
}
}
}
/**
* Site footer
*/
.site-footer {
@include relative-font-size(1.0);
color: $footer-text-color;
background-color: $footer-background-color;
text-align: left;
transition: background-color 0.2s;
.site-footer-inner {
transition: border-top 0.2s;
padding: $spacing-unit * 1.8 0;
}
a {
$a-color: $brand-color;
color: $a-color;
&:hover {
color: lighten($a-color, 10%);
}
}
}
.copyleft {
display: inline-block;
transform: rotate(180deg);
}
/**
* Post header
*/
%post-header {
.post-header {
margin-bottom: $spacing-unit;
}
.post-title {
@include relative-font-size(2.625);
letter-spacing: -1px;
line-height: 1;
@include media-query($on-laptop) {
@include relative-font-size(2.25);
}
}
.post-tags {
padding-right: 150px;
.post-tag {
display: inline-block;
margin: 0 12px 0 0;
}
}
}
/**
* Page content
*/
.page-content {
@extend %flex-1; /* <-- Keep footer on the bottom */
-ms-flex: none; /* <-- Fix IE footer issue */
padding: $spacing-unit * 2 0;
padding-top: 72px;
}
.page-heading {
@include relative-font-size(2);
}
.post-list-heading {
@include relative-font-size(1.75);
}
/**
* Pagination page
*/
.pagination {
.post-list {
margin-left: 0;
list-style: none;
> li {
margin-bottom: $spacing-unit * 1.5;
padding-bottom: 30px;
&:not(:last-child) {
border-bottom: 1px solid #e3e3e3;
}
}
}
.post-title {
margin-bottom: $spacing-unit * 0.2;
transition: 0.2s all;
a {
text-decoration: none;
&:after {
content: 'NEW';
position: absolute;
margin-left: 8px;
margin-top: 3px;
padding: 0px 3px;
background-color: $brand-color;
color: #fff;
font-size: 10px;
font-weight: 600;
border-radius: 2px;
}
&:visited:after {
background-color: #fff;
}
}
}
.post-meta {
font-size: $base-font-size;
color: $grey-color;
margin-bottom: $spacing-unit * 0.5;
}
.post-link {
@include relative-font-size(1.65);
font-weight: $base-font-weight * 1.5;
color: #333;
}
.post-excerpt {
color: #777;
word-break: break-word;
overflow-wrap: break-word;
}
.post-tags .post-tag {
display: inline-block;
text-decoration: none;
border: 1px solid;
padding: 2px 4px;
border-radius: 2px;
transition: color 0.2s;
margin-bottom: 8px;
&:not(:last-child) {
margin-right: 8px;
}
&:hover {
color: #787878;
}
}
.paginator {
text-align: center;
& > .previous:before {
content: ' ';
border: solid #787878;
border-width: 0 2px 2px 0;
display: inline-block;
padding: 4px;
margin-right: 8px;
transform: rotate(135deg);
-webkit-transform: rotate(135deg);
}
& > .next:after {
content: ' ';
border: solid #787878;
border-width: 0 2px 2px 0;
display: inline-block;
padding: 4px;
margin-left: 8px;
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
}
.previous span, .next span {
color: #b3b3b3;
}
.indicator {
padding: 0 15px;
}
}
}
/**
* Posts
*/
.post {
@extend %post-header;
.post-header {
margin: 50px auto 60px;
padding: 0 0 20px;
border-bottom: 1px solid #ebebeb;
.post-title {
margin-bottom: 6px;
}
.post-subtitle {
font-weight: lighter;
}
.post-meta {
color: #808080;
}
}
.post-content {
margin-bottom: $spacing-unit;
overflow-wrap: normal;
word-wrap: normal;
word-break: normal;
h2 {
@include relative-font-size(2);
@include media-query($on-laptop) {
@include relative-font-size(1.75);
}
}
h3 {
@include relative-font-size(1.625);
@include media-query($on-laptop) {
@include relative-font-size(1.375);
}
}
h4 {
@include relative-font-size(1.25);
@include media-query($on-laptop) {
@include relative-font-size(1.125);
}
}
img, svg, iframe {
margin-left: auto;
margin-right: auto;
display: block;
}
h2, h3, h4, h5, h6 {
margin: 60px 0 19px;
}
p, hr {
margin-bottom: 24px;
}
hr {
height: 1px;
background-color: #ebebeb;
border: none;
}
}
.post-related {
&>*:first-child {
@include relative-font-size(1.425);
color: #333;
margin-bottom: 14px;
}
ul {
margin-left: 15px;
.post-link {
@include relative-font-size(1.075);
}
a {
color: #666;
&:hover {
color: #333;
}
&:after {
content: 'NEW';
position: absolute;
margin-left: 8px;
margin-top: 3px;
padding: 0px 3px;
background-color: $brand-color;
color: #fff;
font-size: 10px;
font-weight: 600;
border-radius: 2px;
}
&:visited:after {
background-color: #fff;
}
}
}
}
}
.post-comments {
padding-top: 25px;
}
/**
* Posts misc
*/
.post-nav {
display: flex;
justify-content: space-between;
margin: 72px 0 59px;
padding: 31px 0 0;
a {
@include relative-font-size(1.125);
line-height: 15px;
color: #666;
max-width: 50%;
}
.previous:before {
content: ' ';
border: solid #787878;
border-width: 0 2px 2px 0;
display: inline-block;
padding: 4px;
margin-right: 8px;
transform: rotate(135deg);
-webkit-transform: rotate(135deg);
}
.next:after {
content: ' ';
border: solid #787878;
border-width: 0 2px 2px 0;
display: inline-block;
padding: 4px;
margin-left: 8px;
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
}
}
/**
* Archives page
*/
.page-archives {
.page-archives-list {
margin-left: 0;
list-style: none;
}
.archives-time {
@include relative-font-size(1.5);
&:not(:first-child) {
margin-top: 18px;
}
margin-bottom: 8px;
}
.post-meta {
font-size: $small-font-size;
color: $grey-color;
}
}
/**
* Page banner
*/
.page-banner {
display: block;
position: relative;
height: $banner-height;
background-color: $banner-background;
transition: height 0.2s;
.page-banner-img {
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
& > *:first-child {
@include center-image;
transition: 0.1s all ease-in-out;
}
& > video {
width: 100vw;
object-fit: cover;
}
& > img.img-placeholder {
display: none;
}
}
.wrapper {
height: 100%;
}
.page-banner-inner {
@include vertical-center(relative);
color: $banner-text-color;
padding: 10px 5px;
text-shadow: 1px 1px 2px #33333355;
& > *:first-child {
margin: 0;
> :nth-child(1) {
@include relative-font-size(3.9);
letter-spacing: -1px;
margin-bottom: 0.1em;
font-weight: normal;
transition: 0.2s all;
@include media-query($on-palm) {
@include relative-font-size(1.975);
}
}
> :nth-child(2) {
font-weight: lighter;
margin-bottom: 0.8em;
transition: 0.2s all;
@include media-query($on-palm) {
@include relative-font-size(1.175);
}
}
> :last-child {
margin-bottom: 0;
}
}
.post-subtitle {
@include relative-font-size(1.525);
color: #ffffffcc;
padding-right: 280px;
@include media-query($on-palm) {
padding-right: 0;
}
}
.post-meta {
color: #ffffffcc;
}
.left-vsplit:before {
background: #e3e3e388;
}
.post-tags {
color: #999;
padding-right: 280px;
@include media-query($on-palm) {
padding-right: 0;
}
.post-tag {
@include relative-font-size(1.125);
display: inline-block;
text-decoration: none;
margin: 9px 12px 0 0;
color: #fff;
&:hover {
text-decoration: underline;
}
}
}
}
@include media-query($on-palm) {
height: $banner-height / 1.5;
}
}
/**
* Layout and sidebar
*/
.framework {
@extend %flex;
.main {
@extend %flex-1;
}
.sidebar {
padding-left: 8px;
transition: top 0.2s, display 0.2s;
@include flex-sticky($header-height + 20px);
@include media-query($on-laptop) {
display: none;
}
}
}
/**
* Segments page
*/
.page-segments {
.page-segments-list {
margin-left: 0;
list-style: none;
}
.segment-name {
font-weight: $base-font-weight * 1.5;
margin-bottom: 8px;
position: relative;
@include relative-font-size(1.6);
&:not(:first-child) {
margin-top: 28px;
}
&:hover:before {
content: '#';
left: -1em;
position: absolute;
}
}
.post-meta {
font-size: $small-font-size;
color: $grey-color;
}
li a {
&.post-link {
margin-left: 5px;
}
color: #303030;
&:hover {
color: #000;
}
&:after {
content: 'NEW';
position: absolute;
margin-left: 8px;
margin-top: 3px;
padding: 0px 3px;
background-color: $brand-color;
color: #fff;
font-size: 10px;
font-weight: 600;
border-radius: 2px;
}
&:visited:after {
background-color: #fff;
}
}
}
.left-vsplit:before {
content: "";
display: inline-block;
width: 1px;
height: 10px;
margin: 0 10px;
background-color: #e3e3e3e3;
vertical-align: baseline;
}

View file

@ -1,10 +1,803 @@
---
layout: about
title: About
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="google-translate-customization" content="108d9124921d80c3-80e20d618ff053c8-g4f02ec6f3dba68b7-c">
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>About | Matyáš Caras</title>
<meta name="generator" content="Jekyll v4.3.1">
<meta property="og:title" content="About">
<meta name="author" content="hernikplays">
<meta property="og:locale" content="en_US">
<meta name="description" content="Welcome to my website/blog, full of weird stuff written by yours truly.">
<meta property="og:description" content="Welcome to my website/blog, full of weird stuff written by yours truly.">
<link rel="canonical" href="https://caras.cafe/about.html">
<meta property="og:url" content="https://caras.cafe/about.html">
<meta property="og:site_name" content="Matyáš Caras">
<meta property="og:type" content="website">
<meta name="twitter:card" content="summary">
<meta property="twitter:title" content="About">
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"WebPage","author":{"@type":"Person","name":"hernikplays"},"description":"Welcome to my website/blog, full of weird stuff written by yours truly.","headline":"About","url":"https://caras.cafe/about.html"}</script>
<!-- End Jekyll SEO tag -->
<link rel="shortcut icon" href="">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/typeface-noto-sans@0.0.72/index.min.css">
<link rel="stylesheet" href="/assets/css/main.css">
<script src="/assets/js/main.js"></script><link type="application/atom+xml" rel="alternate" href="https://caras.cafe/feed.xml" title="Matyáš Caras">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js"></script>
<!-- and it's easy to individually load additional languages -->
<script charset="UTF-8" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/languages/go.min.js"></script>
<h2>About</h2>
<script>
// Init highlight js
document.addEventListener('DOMContentLoaded', function(event) {
var els = document.querySelectorAll('pre code')
function addLangData(block) {
var outer = block.parentElement.parentElement.parentElement;
var lang = block.getAttribute('data-lang');
for (var i = 0; i < outer.classList.length; i++) {
var cls = outer.classList[i];
if (cls.startsWith('language-')) {
lang = cls;
break;
}
}
if (!lang) {
cls = block.getAttribute('class');
lang = cls ? cls.replace('hljs ', '') : '';
}
if (lang.startsWith('language-')) {
lang = lang.substr(9);
}
block.setAttribute('class', 'hljs ' + lang);
block.parentNode.setAttribute('data-lang', lang);
}
function addBadge(block) {
var enabled = ('true' || 'true').toLowerCase();
if (enabled == 'true') {
var pre = block.parentElement;
pre.classList.add('badge');
}
}
function handle(block) {
addLangData(block);
addBadge(block)
hljs.highlightBlock(block);
}
for (var i = 0; i < els.length; i++) {
var el = els[i];
handle(el);
}
});
</script>
<style>
/* code language badge */
pre.badge::before {
content: attr(data-lang);
color: #fff;
background-color: #ff4e00;
padding: 0 .5em;
border-radius: 0 2px;
text-transform: uppercase;
text-align: center;
min-width: 32px;
display: inline-block;
position: absolute;
right: 0;
}
/* fix wrong badge display for firefox browser */
code > table pre::before {
display: none;
}
</style>
</head>
<body>
<header class="site-header " role="banner">
<div class="wrapper">
<div class="site-header-inner">
<span class="site-brand"><a class="site-brand-inner" rel="author" href="/">
<img class="site-favicon" title="Matyáš Caras" src="" onerror="this.style.display='none'">
Matyáš Caras
</a>
</span><nav class="site-nav">
<input type="checkbox" id="nav-trigger" class="nav-trigger">
<label for="nav-trigger">
<span class="menu-icon">
<svg viewbox="0 0 18 15" width="18px" height="15px">
<path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"></path>
</svg>
</span>
</label>
<div class="trigger">
<a class="page-link" href="/about.html">ABOUT</a><a class="page-link" href="/archives.html">ARCHIVES</a><a class="page-link" href="/categories.html">CATEGORIES</a><a class="page-link" href="/">HOME</a><a class="page-link" href="/tags.html">TAGS</a>
</div>
</nav>
</div>
</div>
</header>
<script>
function initHeader() {
var lastScrollY = getScrollPos().y;
var documentElement = document.documentElement;
function storeScrollData() {
var y = getScrollPos().y;var scrollStatus = "";
if (y <= 0) {
scrollStatus = "top";
} else if ((window.innerHeight + y) >= document.body.offsetHeight) {
scrollStatus = "bottom";
} else {
var isScrollDown = (y - lastScrollY > 0) ? true : false;
scrollStatus = isScrollDown ? "down" : "up";
}
lastScrollY = y;
documentElement.setAttribute("data-scroll-status", scrollStatus);
}
window.addEventListener('scroll', function(e) {
storeScrollData();
});
storeScrollData();
}
document.addEventListener('DOMContentLoaded', initHeader);
</script>
<script>
function hashLocate(hashValue) {
hashValue = hashValue.replace(/^.*#h-/, '');
hashValue = decodeURIComponent(hashValue);
var element = document.getElementById(hashValue);
if (!element) {
return;
}
var header = document.querySelector('header.site-header');
var headerRect = header.getBoundingClientRect();
var headerTop = Math.floor(headerRect.top);
var headerHeight = Math.floor(headerRect.height);
var scrollPos = getScrollPos();
var offsetY = element.offsetTop - (headerTop + headerHeight + 20);
if (offsetY == scrollPos.y) {
return;
}
if (headerTop == 0 && offsetY > scrollPos.y) {
offsetY += headerHeight + 2;
} else if (headerTop < 0 && offsetY < scrollPos.y) {
offsetY -= headerHeight - 2;
}
smoothScrollTo(offsetY);
}
// The first event occurred
window.addEventListener('load', function(event) {
if (window.location.hash) {
hashLocate(window.location.hash);
}
});
// The first event occurred
window.addEventListener('click', function(event) {
if (event.target.tagName.toLowerCase() == 'a') {
hashLocate(event.target.getAttribute('href'));
}
});
</script>
<div class="theme-toggle">
<input type="checkbox" id="theme-switch">
<label for="theme-switch">
<div class="toggle"></div>
<div class="names">
<p class="light">Light</p>
<p class="dark">Dark</p>
</div>
</label>
</div>
<script>
(function() {
var sw = document.getElementById('theme-switch');
var html = document.getElementsByTagName('html')[0];
var nightModeOption = ('auto' || 'auto').toLowerCase();
var storage = nightModeOption === 'manual'
? localStorage
: sessionStorage;
var themeData = loadThemeData();
function saveThemeData(data) {
storage.setItem('theme', JSON.stringify(data));
}
function loadThemeData() {
var data = storage.getItem('theme');
try {
data = JSON.parse(data ? data : '');
} catch(e) {
data = { nightShift: undefined, autoToggleAt: 0 };
saveThemeData(data);
}
return data;
}
function handleThemeToggle(nightShift) {
themeData.nightShift = nightShift;
saveThemeData(themeData);
html.dataset.theme = nightShift ? 'dark' : 'light';
setTimeout(function() {
sw.checked = nightShift ? true : false;
}, 50);
}
function autoThemeToggle() {
// Next time point of theme toggle
var now = new Date();
var toggleAt = new Date();
var hours = now.getHours();
var nightShift = hours >= 19 || hours <=7;
if (nightShift) {
if (hours > 7) {
toggleAt.setDate(toggleAt.getDate() + 1);
}
toggleAt.setHours(7);
} else {
toggleAt.setHours(19);
}
toggleAt.setMinutes(0);
toggleAt.setSeconds(0);
toggleAt.setMilliseconds(0)
var delay = toggleAt.getTime() - now.getTime();
// auto toggle theme mode
setTimeout(function() {
handleThemeToggle(!nightShift);
}, delay);
return {
nightShift: nightShift,
toggleAt: toggleAt.getTime()
};
}
// Listen the theme toggle event
sw.addEventListener('change', function(event) {
handleThemeToggle(event.target.checked);
});
if (nightModeOption == 'auto') {
var data = autoThemeToggle();
// Toggle theme by local setting
if (data.toggleAt > themeData.autoToggleAt) {
themeData.autoToggleAt = data.toggleAt;
handleThemeToggle(data.nightShift);
} else {
handleThemeToggle(themeData.nightShift);
}
} else if (nightModeOption == 'manual') {
handleThemeToggle(themeData.nightShift);
} else {
var nightShift = themeData.nightShift;
if (nightShift === undefined) {
nightShift = nightModeOption === 'on';
}
handleThemeToggle(nightShift);
}
})();
</script>
<div id="click-to-top" class="click-to-top">
<i class="fa fa-arrow-up"></i>
</div>
<script>
(function () {
const clickToTop = document.getElementById('click-to-top');
window.addEventListener('scroll', () => {
if (window.scrollY > 100) {
clickToTop.classList.add('show')
}else {
clickToTop.classList.remove('show')
}
});
clickToTop.addEventListener('click', () => {
window.smoothScrollTo(0);
});
})();
</script>
<main class="page-content" aria-label="Content">
<div class="wrapper">
<div class="framework">
<section class="main">
<div class="post">
<section>
<article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">
<div class="post-content e-content" itemprop="articleBody">
<h2>About</h2>
<p>
I'm Matyáš Caras, I study IT in the Czech Republic and create software projects.
</p>
</div>
</article>
<div class="post-comments"> <div id="gitment_thread" class="giscus"></div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/theme-next/theme-next-gitment@1/default.css">
<script src="https://cdn.jsdelivr.net/gh/theme-next/theme-next-gitment@1/gitment.browser.js"></script>
<script src="https://giscus.app/client.js" data-repo="hernikplays/blog" data-repo-id="R_kgDOHr2B6w" data-category="General" data-category-id="DIC_kwDOHr2B684CSIhA" data-mapping="pathname" data-strict="0" data-reactions-enabled="1" data-emit-metadata="0" data-input-position="top" data-theme="transparent_dark" data-lang="en" data-loading="lazy" crossorigin="anonymous" async>
</script>
</div></section>
</div>
</section>
<section class="sidebar" style="margin-left: 15px;">
<!-- Get sidebar items --><style type="text/css" media="screen">
.post-menu ul {
list-style: none;
padding: 0;
margin: 0;
}
</style>
<div class="post-menu">
<div class="post-menu-title">TOC</div>
<div class="post-menu-content"></div>
</div>
<script>
function generateContent() {
var menu = document.querySelector(".post-menu");
var menuContent = menu.querySelector(".post-menu-content");
var headings = document.querySelector(".post-content").querySelectorAll("h2, h3, h4, h5, h6");
// Hide menu when no headings
if (headings.length === 0) {
return menu.style.display = "none";
}
// Generate post menu
var menuHTML = '';
for (var i = 0; i < headings.length; i++) {
var h = headings[i];
menuHTML += (
'<li class="h-' + h.tagName.toLowerCase() + '">'
+ '<a href="#h-' + h.getAttribute('id') + '">' + h.textContent + '</a></li>');
}
menuContent.innerHTML = '<ul>' + menuHTML + '</ul>';
// The header element
var header = document.querySelector('header.site-header');
function doMenuCollapse(index, over_items) {
var items = menuContent.firstChild.children;
if (over_items == undefined) {
over_items = 20;
}
if (items.length < over_items) {
return;
}
var activeItem = items[index];
var beginItem = activeItem
var endItem = activeItem
var beginIndex = index;
var endIndex = index + 1;
while (beginIndex >= 0
&& !items[beginIndex].classList.contains('h-h2')) {
beginIndex -= 1;
}
while (endIndex < items.length
&& !items[endIndex].classList.contains('h-h2')) {
endIndex += 1;
}
for (var i = 0; i < beginIndex; i++) {
item = items[i]
if (!item.classList.contains('h-h2')) {
item.style.display = 'none';
}
}
for (var i = beginIndex + 1; i < endIndex; i++) {
item = items[i]
// if (!item.classList.contains('h-h2')) {
item.style.display = '';
// }
}
for (var i = endIndex; i < items.length; i++) {
item = items[i]
if (!item.classList.contains('h-h2')) {
item.style.display = 'none';
}
}
}
// Init menu collapsed
doMenuCollapse(-1);
// Active the menu item
window.addEventListener('scroll', function (event) {
var lastActive = menuContent.querySelector('.active');
var changed = true;
var activeIndex = -1;
for (var i = headings.length - 1; i >= 0; i--) {
var h = headings[i];
var headingRect = h.getBoundingClientRect();
var headerRect = header.getBoundingClientRect();
var headerTop = Math.floor(headerRect.top);
var headerHeight = Math.floor(headerRect.height);
var headerHeight = headerTop + headerHeight + 20;
if (headingRect.top <= headerHeight) {
var id = 'h-' + h.getAttribute('id');
var a = menuContent.querySelector('a[href="#' + id + '"]');
var curActive = a.parentNode;
if (curActive) {
curActive.classList.add('active');
activeIndex = i;
}
if (lastActive == curActive) {
changed = false;
}
break;
}
}
if (changed) {
if (lastActive) {
lastActive.classList.remove('active');
}
doMenuCollapse(activeIndex);
}
event.preventDefault();
});
}
generateContent();
</script>
</section>
</div>
</div>
</main><footer class="site-footer h-card">
<data class="u-url" href="/"></data>
<div class="wrapper">
<div class="site-footer-inner">
<div>Copyright © 2021-2022 hernikplays</div>
<div>Powered by <a title="Jekyll is a simple, blog-aware, static site
generator." href="https://jekyllrb.com/">Jekyll</a> &amp; <a title="Yat, yet
another theme." href="https://github.com/jeffreytse/jekyll-theme-yat">Yat Theme</a>.</div>
<div><a rel="me" href="https://social.linux.pizza/@hernik">Mastodon</a></div>
<div class="footer-col rss-subscribe">Subscribe <a href="/feed.xml">via RSS</a>
</div>
</div>
</div>
</footer>
</body>
</html>

View file

@ -1,4 +1,772 @@
---
layout: archives
title: Archives
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="google-translate-customization" content="108d9124921d80c3-80e20d618ff053c8-g4f02ec6f3dba68b7-c">
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>Archives | Matyáš Caras</title>
<meta name="generator" content="Jekyll v4.3.1">
<meta property="og:title" content="Archives">
<meta name="author" content="hernikplays">
<meta property="og:locale" content="en_US">
<meta name="description" content="Welcome to my website/blog, full of weird stuff written by yours truly.">
<meta property="og:description" content="Welcome to my website/blog, full of weird stuff written by yours truly.">
<link rel="canonical" href="https://caras.cafe/archives.html">
<meta property="og:url" content="https://caras.cafe/archives.html">
<meta property="og:site_name" content="Matyáš Caras">
<meta property="og:type" content="website">
<meta name="twitter:card" content="summary">
<meta property="twitter:title" content="Archives">
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"WebPage","author":{"@type":"Person","name":"hernikplays"},"description":"Welcome to my website/blog, full of weird stuff written by yours truly.","headline":"Archives","url":"https://caras.cafe/archives.html"}</script>
<!-- End Jekyll SEO tag -->
<link rel="shortcut icon" href="">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/typeface-noto-sans@0.0.72/index.min.css">
<link rel="stylesheet" href="/assets/css/main.css">
<script src="/assets/js/main.js"></script><link type="application/atom+xml" rel="alternate" href="https://caras.cafe/feed.xml" title="Matyáš Caras">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js"></script>
<!-- and it's easy to individually load additional languages -->
<script charset="UTF-8" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/languages/go.min.js"></script>
<script>
// Init highlight js
document.addEventListener('DOMContentLoaded', function(event) {
var els = document.querySelectorAll('pre code')
function addLangData(block) {
var outer = block.parentElement.parentElement.parentElement;
var lang = block.getAttribute('data-lang');
for (var i = 0; i < outer.classList.length; i++) {
var cls = outer.classList[i];
if (cls.startsWith('language-')) {
lang = cls;
break;
}
}
if (!lang) {
cls = block.getAttribute('class');
lang = cls ? cls.replace('hljs ', '') : '';
}
if (lang.startsWith('language-')) {
lang = lang.substr(9);
}
block.setAttribute('class', 'hljs ' + lang);
block.parentNode.setAttribute('data-lang', lang);
}
function addBadge(block) {
var enabled = ('true' || 'true').toLowerCase();
if (enabled == 'true') {
var pre = block.parentElement;
pre.classList.add('badge');
}
}
function handle(block) {
addLangData(block);
addBadge(block)
hljs.highlightBlock(block);
}
for (var i = 0; i < els.length; i++) {
var el = els[i];
handle(el);
}
});
</script>
<style>
/* code language badge */
pre.badge::before {
content: attr(data-lang);
color: #fff;
background-color: #ff4e00;
padding: 0 .5em;
border-radius: 0 2px;
text-transform: uppercase;
text-align: center;
min-width: 32px;
display: inline-block;
position: absolute;
right: 0;
}
/* fix wrong badge display for firefox browser */
code > table pre::before {
display: none;
}
</style>
</head>
<body>
<header class="site-header " role="banner">
<div class="wrapper">
<div class="site-header-inner">
<span class="site-brand"><a class="site-brand-inner" rel="author" href="/">
<img class="site-favicon" title="Matyáš Caras" src="" onerror="this.style.display='none'">
Matyáš Caras
</a>
</span><nav class="site-nav">
<input type="checkbox" id="nav-trigger" class="nav-trigger">
<label for="nav-trigger">
<span class="menu-icon">
<svg viewbox="0 0 18 15" width="18px" height="15px">
<path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"></path>
</svg>
</span>
</label>
<div class="trigger">
<a class="page-link" href="/about.html">ABOUT</a><a class="page-link" href="/archives.html">ARCHIVES</a><a class="page-link" href="/categories.html">CATEGORIES</a><a class="page-link" href="/">HOME</a><a class="page-link" href="/tags.html">TAGS</a>
</div>
</nav>
</div>
</div>
</header>
<script>
function initHeader() {
var lastScrollY = getScrollPos().y;
var documentElement = document.documentElement;
function storeScrollData() {
var y = getScrollPos().y;var scrollStatus = "";
if (y <= 0) {
scrollStatus = "top";
} else if ((window.innerHeight + y) >= document.body.offsetHeight) {
scrollStatus = "bottom";
} else {
var isScrollDown = (y - lastScrollY > 0) ? true : false;
scrollStatus = isScrollDown ? "down" : "up";
}
lastScrollY = y;
documentElement.setAttribute("data-scroll-status", scrollStatus);
}
window.addEventListener('scroll', function(e) {
storeScrollData();
});
storeScrollData();
}
document.addEventListener('DOMContentLoaded', initHeader);
</script>
<script>
function hashLocate(hashValue) {
hashValue = hashValue.replace(/^.*#h-/, '');
hashValue = decodeURIComponent(hashValue);
var element = document.getElementById(hashValue);
if (!element) {
return;
}
var header = document.querySelector('header.site-header');
var headerRect = header.getBoundingClientRect();
var headerTop = Math.floor(headerRect.top);
var headerHeight = Math.floor(headerRect.height);
var scrollPos = getScrollPos();
var offsetY = element.offsetTop - (headerTop + headerHeight + 20);
if (offsetY == scrollPos.y) {
return;
}
if (headerTop == 0 && offsetY > scrollPos.y) {
offsetY += headerHeight + 2;
} else if (headerTop < 0 && offsetY < scrollPos.y) {
offsetY -= headerHeight - 2;
}
smoothScrollTo(offsetY);
}
// The first event occurred
window.addEventListener('load', function(event) {
if (window.location.hash) {
hashLocate(window.location.hash);
}
});
// The first event occurred
window.addEventListener('click', function(event) {
if (event.target.tagName.toLowerCase() == 'a') {
hashLocate(event.target.getAttribute('href'));
}
});
</script>
<div class="theme-toggle">
<input type="checkbox" id="theme-switch">
<label for="theme-switch">
<div class="toggle"></div>
<div class="names">
<p class="light">Light</p>
<p class="dark">Dark</p>
</div>
</label>
</div>
<script>
(function() {
var sw = document.getElementById('theme-switch');
var html = document.getElementsByTagName('html')[0];
var nightModeOption = ('auto' || 'auto').toLowerCase();
var storage = nightModeOption === 'manual'
? localStorage
: sessionStorage;
var themeData = loadThemeData();
function saveThemeData(data) {
storage.setItem('theme', JSON.stringify(data));
}
function loadThemeData() {
var data = storage.getItem('theme');
try {
data = JSON.parse(data ? data : '');
} catch(e) {
data = { nightShift: undefined, autoToggleAt: 0 };
saveThemeData(data);
}
return data;
}
function handleThemeToggle(nightShift) {
themeData.nightShift = nightShift;
saveThemeData(themeData);
html.dataset.theme = nightShift ? 'dark' : 'light';
setTimeout(function() {
sw.checked = nightShift ? true : false;
}, 50);
}
function autoThemeToggle() {
// Next time point of theme toggle
var now = new Date();
var toggleAt = new Date();
var hours = now.getHours();
var nightShift = hours >= 19 || hours <=7;
if (nightShift) {
if (hours > 7) {
toggleAt.setDate(toggleAt.getDate() + 1);
}
toggleAt.setHours(7);
} else {
toggleAt.setHours(19);
}
toggleAt.setMinutes(0);
toggleAt.setSeconds(0);
toggleAt.setMilliseconds(0)
var delay = toggleAt.getTime() - now.getTime();
// auto toggle theme mode
setTimeout(function() {
handleThemeToggle(!nightShift);
}, delay);
return {
nightShift: nightShift,
toggleAt: toggleAt.getTime()
};
}
// Listen the theme toggle event
sw.addEventListener('change', function(event) {
handleThemeToggle(event.target.checked);
});
if (nightModeOption == 'auto') {
var data = autoThemeToggle();
// Toggle theme by local setting
if (data.toggleAt > themeData.autoToggleAt) {
themeData.autoToggleAt = data.toggleAt;
handleThemeToggle(data.nightShift);
} else {
handleThemeToggle(themeData.nightShift);
}
} else if (nightModeOption == 'manual') {
handleThemeToggle(themeData.nightShift);
} else {
var nightShift = themeData.nightShift;
if (nightShift === undefined) {
nightShift = nightModeOption === 'on';
}
handleThemeToggle(nightShift);
}
})();
</script>
<div id="click-to-top" class="click-to-top">
<i class="fa fa-arrow-up"></i>
</div>
<script>
(function () {
const clickToTop = document.getElementById('click-to-top');
window.addEventListener('scroll', () => {
if (window.scrollY > 100) {
clickToTop.classList.add('show')
}else {
clickToTop.classList.remove('show')
}
});
clickToTop.addEventListener('click', () => {
window.smoothScrollTo(0);
});
})();
</script>
<main class="page-content" aria-label="Content">
<div class="wrapper">
<div class="framework">
<section class="main">
<div class="page-segments">
<ul class="page-segments-list">
<h2 id="2022" class="segment-name">2022</h2>
<li>
<span class="post-meta">Oct 22, 2022</span>
<span>
<a class="post-link" href="/tutori%C3%A1l/2022/10/22/rpi-arch.html">
Instalujeme Arch Linux ARM na Raspberry Pi 3
</a>
</span>
</li>
<li>
<span class="post-meta">Jul 19, 2022</span>
<span>
<a class="post-link" href="/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn.html">
NordVPN - Jste opravdu v takovém nebezpečí?
</a>
</span>
</li>
<li>
<span class="post-meta">May 31, 2022</span>
<span>
<a class="post-link" href="/vychyt%C3%A1vky/2022/05/31/codespaces.html">
GitHub Codespaces aneb VS Code na VPS
</a>
</span>
</li>
<li>
<span class="post-meta">May 22, 2022</span>
<span>
<a class="post-link" href="/programov%C3%A1n%C3%AD/2022/05/22/automatizace.html">
Automatizace, automatizace, automatizace
</a>
</span>
</li>
</ul>
</div>
</section>
<section class="sidebar" style="margin-left: 15px;">
<!-- Get sidebar items -->
<div class="common-list">
<ul>
<li>
<a href="/index.html">
All<span>4</span>
</a>
</li>
<li>
<a href="/archives.html#h-2022">
2022 <span>4</span>
</a>
</li>
</ul>
</div>
</section>
</div>
</div>
</main><footer class="site-footer h-card">
<data class="u-url" href="/"></data>
<div class="wrapper">
<div class="site-footer-inner">
<div>Copyright © 2021-2022 hernikplays</div>
<div>Powered by <a title="Jekyll is a simple, blog-aware, static site
generator." href="https://jekyllrb.com/">Jekyll</a> &amp; <a title="Yat, yet
another theme." href="https://github.com/jeffreytse/jekyll-theme-yat">Yat Theme</a>.</div>
<div><a rel="me" href="https://social.linux.pizza/@hernik">Mastodon</a></div>
<div class="footer-col rss-subscribe">Subscribe <a href="/feed.xml">via RSS</a>
</div>
</div>
</div>
</footer>
</body>
</html>

573
assets/css/main.css Normal file
View file

@ -0,0 +1,573 @@
/** Reset some basic elements */
body, h1, h2, h3, h4, h5, h6, p, blockquote, pre, hr, dl, dd, ol, ul, figure { margin: 0; padding: 0; }
/** Basic styling */
body { font-family: Helvetica, Arial, Oswald, sans-serif; font-weight: 400; font-size: 14px; font-display: swap; line-height: 1.6; color: #454545; background-color: #fff; -webkit-text-size-adjust: 100%; -webkit-font-feature-settings: "kern" 1; -moz-font-feature-settings: "kern" 1; -o-font-feature-settings: "kern" 1; font-feature-settings: "kern" 1; font-kerning: normal; display: flex; min-height: 100vh; flex-direction: column; }
/** Set `margin-bottom` to maintain vertical rhythm */
h1, h2, h3, h4, h5, h6, p, blockquote, pre, ul, ol, dl, figure { margin-bottom: 15px; }
/** `main` element */
main { display: block; /* Default value of `display` of `main` element is 'inline' in IE 11. */ }
/** Images */
img { max-width: 100%; vertical-align: middle; }
/** Figures */
figure > img { display: block; }
figcaption { font-size: 12.25px; }
/** Lists */
ul, ol { margin-left: 30px; }
li > ul, li > ol { margin-bottom: 0; }
/** Headings */
h1, h2, h3, h4, h5, h6 { font-weight: 600; }
/** Links */
a { color: #ff5100; text-decoration: none; }
a:hover { text-decoration: underline; }
.social-media-list a:hover { text-decoration: none; }
.social-media-list a:hover .username { text-decoration: underline; }
/** Blockquotes */
blockquote { color: #828282; border-left: 4px solid #e8e8e8; padding-left: 15px; font-size: 15.75px; letter-spacing: -1px; font-style: italic; }
blockquote > :last-child { margin-bottom: 0; }
/** Code formatting */
pre, code { font-size: 13.125px; color: #454545; }
*:not(pre) > code { padding: 3px 6px; border-radius: 3px; background-color: #eee; margin: 0 5px; }
pre { overflow-x: auto; position: relative; background-color: #f0f0f0; }
pre > code { display: inline-block; padding: 20px !important; background-color: transparent; border: 0; }
pre table, pre pre { margin-bottom: 0; }
pre table .gutter, pre table .code, pre pre .gutter, pre pre .code { padding: 6px; border: none; }
/** Wrapper */
.wrapper { max-width: 920px; margin: auto; padding-right: 30px; padding-left: 30px; }
/** Clearfix */
.wrapper:after { content: ""; display: table; clear: both; }
/** Tables */
table { display: block; margin-bottom: 30px; width: 100%; text-align: left; color: #525252; border-collapse: collapse; overflow: auto; }
table tr:nth-child(even) { background-color: #f7f7f7; }
table th, table td { padding: 10px 15px; }
table th { background-color: #f0f0f0; border: 1px solid #dedede; border-bottom-color: #c9c9c9; }
table td { border: 1px solid #e8e8e8; }
/** Flex layout */
.framework { display: flex; }
.framework .main, .page-content { flex: 1; min-width: 0; /* <-- fix flexbox width with pre tags */ }
/** Flex sticky */
/** Vertical center */
/** Horizontal center */
/** Center background image */
/** Animation for transparent header */
html[data-header-transparent] header.site-header { position: fixed; }
html[data-scroll-status='top'] header.site-header-transparent { height: 0; margin-top: 12px; background-color: transparent; transition: 0.1s height,background-color,box-shadow; }
html[data-scroll-status='top'] header.site-header-transparent.site-header .site-brand-inner, html[data-scroll-status='top'] header.site-header-transparent.site-header .page-link { color: #fff; transition: 0.1s color; }
@media screen and (max-width: 800px) { html[data-scroll-status='top'] header.site-header-transparent.site-header .page-link { color: black; } html[data-scroll-status='top'] header.site-header-transparent.site-header .menu-icon > svg { fill: #fdfdfd; } }
html[data-scroll-status='top'] footer.site-footer { color: unset; background-color: transparent; }
html[data-scroll-status='top'] footer.site-footer .site-footer-inner { border-top: solid 1px #eee; }
html[data-scroll-status='down'] header.site-header { top: -63.84px; }
html[data-scroll-status='down'] .framework .sidebar { top: 20px; }
/** Site header */
.site-header { background-color: #ffffff; height: 63.84px; width: 100%; transition: height 0.2s, text-shadow 0.2s, top 0.2s; box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.06); position: sticky; position: -moz-sticky; /* <-- fix sticky compatibility issue */ position: -ms-sticky; position: -o-sticky; position: -webkit-sticky; align-self: flex-start; /* <-- fix the sticky not work issue */ transform: scale(0.9999); /* <-- fix the sticky x overflow issue */ top: 0; z-index: 1000; }
.site-header > .wrapper { margin: 0 60px; padding: 0; max-width: 100%; transition: 0.2s margin; }
@media screen and (max-width: 1024px) { .site-header > .wrapper { margin: 0 20px; max-width: unset; } }
.site-header a { text-decoration: none; }
.site-header .site-header-inner { position: relative; }
.site-brand { line-height: 63.84px; margin-right: 50px; }
.site-brand .site-brand-inner { font-size: 15.75px; font-weight: 400; letter-spacing: -1px; transition: 0.1s filter color; }
.site-brand .site-brand-inner, .site-brand .site-brand-inner:visited { color: black; }
.site-brand .site-brand-inner .site-favicon { display: inline-block; height: 42.56px; margin-right: 5px; }
.site-nav { font-size: 15.75px; line-height: 63.84px; position: absolute; right: 0; top: 0; }
.site-nav .nav-trigger { display: none; }
.site-nav .menu-icon { display: none; }
.site-nav .page-link { line-height: 1.6; color: black; transition: 0.1s ease-in-out; }
.site-nav .page-link:not(:last-child) { margin-right: 24px; }
.site-nav .page-link:not(:last-child):hover { text-decoration: underline; }
@media screen and (max-width: 800px) { .site-nav { position: absolute; top: 0; text-align: left; } .site-nav label[for="nav-trigger"] { display: block; z-index: 2; cursor: pointer; } .site-nav .menu-icon { display: block; float: right; text-align: center; } .site-nav .menu-icon > svg { fill: black; transition: 0.1s fill; } .site-nav input ~ .trigger { clear: both; display: none; border-radius: 3px; box-shadow: 1px 1px 1px 1px rgba(0, 0, 0, 0.06); } .site-nav input:checked ~ .trigger { display: block; background: #ffffff; } .site-nav .page-link { display: block; padding: 5px 10px; color: black; margin: 0 25px; } }
/** Site footer */
.site-footer { font-size: 14px; color: #404040; background-color: #f2f2f2; text-align: left; transition: background-color 0.2s; }
.site-footer .site-footer-inner { transition: border-top 0.2s; padding: 54px 0; }
.site-footer a { color: #ff5100; }
.site-footer a:hover { color: #ff7433; }
.copyleft { display: inline-block; transform: rotate(180deg); }
/** Post header */
.post .post-header { margin-bottom: 30px; }
.post .post-title { font-size: 36.75px; letter-spacing: -1px; line-height: 1; }
@media screen and (max-width: 800px) { .post .post-title { font-size: 31.5px; } }
.post .post-tags { padding-right: 150px; }
.post .post-tags .post-tag { display: inline-block; margin: 0 12px 0 0; }
/** Page content */
.page-content { /* <-- Keep footer on the bottom */ -ms-flex: none; /* <-- Fix IE footer issue */ padding: 60px 0; padding-top: 72px; }
.page-heading { font-size: 28px; }
.post-list-heading { font-size: 24.5px; }
/** Pagination page */
.pagination .post-list { margin-left: 0; list-style: none; }
.pagination .post-list > li { margin-bottom: 45px; padding-bottom: 30px; }
.pagination .post-list > li:not(:last-child) { border-bottom: 1px solid #e3e3e3; }
.pagination .post-title { margin-bottom: 6px; transition: 0.2s all; }
.pagination .post-title a { text-decoration: none; }
.pagination .post-title a:after { content: 'NEW'; position: absolute; margin-left: 8px; margin-top: 3px; padding: 0px 3px; background-color: #ff5100; color: #fff; font-size: 10px; font-weight: 600; border-radius: 2px; }
.pagination .post-title a:visited:after { background-color: #fff; }
.pagination .post-meta { font-size: 14px; color: #828282; margin-bottom: 15px; }
.pagination .post-link { font-size: 23.1px; font-weight: 600; color: #333; }
.pagination .post-excerpt { color: #777; word-break: break-word; overflow-wrap: break-word; }
.pagination .post-tags .post-tag { display: inline-block; text-decoration: none; border: 1px solid; padding: 2px 4px; border-radius: 2px; transition: color 0.2s; margin-bottom: 8px; }
.pagination .post-tags .post-tag:not(:last-child) { margin-right: 8px; }
.pagination .post-tags .post-tag:hover { color: #787878; }
.pagination .paginator { text-align: center; }
.pagination .paginator > .previous:before { content: ' '; border: solid #787878; border-width: 0 2px 2px 0; display: inline-block; padding: 4px; margin-right: 8px; transform: rotate(135deg); -webkit-transform: rotate(135deg); }
.pagination .paginator > .next:after { content: ' '; border: solid #787878; border-width: 0 2px 2px 0; display: inline-block; padding: 4px; margin-left: 8px; transform: rotate(-45deg); -webkit-transform: rotate(-45deg); }
.pagination .paginator .previous span, .pagination .paginator .next span { color: #b3b3b3; }
.pagination .paginator .indicator { padding: 0 15px; }
/** Posts */
.post .post-header { margin: 50px auto 60px; padding: 0 0 20px; border-bottom: 1px solid #ebebeb; }
.post .post-header .post-title { margin-bottom: 6px; }
.post .post-header .post-subtitle { font-weight: lighter; }
.post .post-header .post-meta { color: #808080; }
.post .post-content { margin-bottom: 30px; overflow-wrap: normal; word-wrap: normal; word-break: normal; }
.post .post-content h2 { font-size: 28px; }
@media screen and (max-width: 800px) { .post .post-content h2 { font-size: 24.5px; } }
.post .post-content h3 { font-size: 22.75px; }
@media screen and (max-width: 800px) { .post .post-content h3 { font-size: 19.25px; } }
.post .post-content h4 { font-size: 17.5px; }
@media screen and (max-width: 800px) { .post .post-content h4 { font-size: 15.75px; } }
.post .post-content img, .post .post-content svg, .post .post-content iframe { margin-left: auto; margin-right: auto; display: block; }
.post .post-content h2, .post .post-content h3, .post .post-content h4, .post .post-content h5, .post .post-content h6 { margin: 60px 0 19px; }
.post .post-content p, .post .post-content hr { margin-bottom: 24px; }
.post .post-content hr { height: 1px; background-color: #ebebeb; border: none; }
.post .post-related > *:first-child { font-size: 19.95px; color: #333; margin-bottom: 14px; }
.post .post-related ul { margin-left: 15px; }
.post .post-related ul .post-link { font-size: 15.05px; }
.post .post-related ul a { color: #666; }
.post .post-related ul a:hover { color: #333; }
.post .post-related ul a:after { content: 'NEW'; position: absolute; margin-left: 8px; margin-top: 3px; padding: 0px 3px; background-color: #ff5100; color: #fff; font-size: 10px; font-weight: 600; border-radius: 2px; }
.post .post-related ul a:visited:after { background-color: #fff; }
.post-comments { padding-top: 25px; }
/** Posts misc */
.post-nav { display: flex; justify-content: space-between; margin: 72px 0 59px; padding: 31px 0 0; }
.post-nav a { font-size: 15.75px; line-height: 15px; color: #666; max-width: 50%; }
.post-nav .previous:before { content: ' '; border: solid #787878; border-width: 0 2px 2px 0; display: inline-block; padding: 4px; margin-right: 8px; transform: rotate(135deg); -webkit-transform: rotate(135deg); }
.post-nav .next:after { content: ' '; border: solid #787878; border-width: 0 2px 2px 0; display: inline-block; padding: 4px; margin-left: 8px; transform: rotate(-45deg); -webkit-transform: rotate(-45deg); }
/** Archives page */
.page-archives .page-archives-list { margin-left: 0; list-style: none; }
.page-archives .archives-time { font-size: 21px; margin-bottom: 8px; }
.page-archives .archives-time:not(:first-child) { margin-top: 18px; }
.page-archives .post-meta { font-size: 12.25px; color: #828282; }
/** Page banner */
.page-banner { display: block; position: relative; height: 640px; background-color: rgba(0, 0, 0, 0.8); transition: height 0.2s; }
.page-banner .page-banner-img { position: absolute; width: 100%; height: 100%; overflow: hidden; }
.page-banner .page-banner-img > *:first-child { height: 100%; max-width: 1000%; background-size: cover; background-position: center center; overflow: hidden; transition: 0.1s all ease-in-out; }
.page-banner .page-banner-img > video { width: 100vw; object-fit: cover; }
.page-banner .page-banner-img > img.img-placeholder { display: none; }
.page-banner .wrapper { height: 100%; }
.page-banner .page-banner-inner { position: relative; top: 50%; transform: translateY(-50%); color: #fdfdfd; padding: 10px 5px; text-shadow: 1px 1px 2px #33333355; }
.page-banner .page-banner-inner > *:first-child { margin: 0; }
.page-banner .page-banner-inner > *:first-child > :nth-child(1) { font-size: 54.6px; letter-spacing: -1px; margin-bottom: 0.1em; font-weight: normal; transition: 0.2s all; }
@media screen and (max-width: 600px) { .page-banner .page-banner-inner > *:first-child > :nth-child(1) { font-size: 27.65px; } }
.page-banner .page-banner-inner > *:first-child > :nth-child(2) { font-weight: lighter; margin-bottom: 0.8em; transition: 0.2s all; }
@media screen and (max-width: 600px) { .page-banner .page-banner-inner > *:first-child > :nth-child(2) { font-size: 16.45px; } }
.page-banner .page-banner-inner > *:first-child > :last-child { margin-bottom: 0; }
.page-banner .page-banner-inner .post-subtitle { font-size: 21.35px; color: #ffffffcc; padding-right: 280px; }
@media screen and (max-width: 600px) { .page-banner .page-banner-inner .post-subtitle { padding-right: 0; } }
.page-banner .page-banner-inner .post-meta { color: #ffffffcc; }
.page-banner .page-banner-inner .left-vsplit:before { background: #e3e3e388; }
.page-banner .page-banner-inner .post-tags { color: #999; padding-right: 280px; }
@media screen and (max-width: 600px) { .page-banner .page-banner-inner .post-tags { padding-right: 0; } }
.page-banner .page-banner-inner .post-tags .post-tag { font-size: 15.75px; display: inline-block; text-decoration: none; margin: 9px 12px 0 0; color: #fff; }
.page-banner .page-banner-inner .post-tags .post-tag:hover { text-decoration: underline; }
@media screen and (max-width: 600px) { .page-banner { height: 426.6666666667px; } }
/** Layout and sidebar */
.framework .sidebar { padding-left: 8px; transition: top 0.2s, display 0.2s; position: sticky; position: -moz-sticky; /* <-- fix sticky compatibility issue */ position: -ms-sticky; position: -o-sticky; position: -webkit-sticky; align-self: flex-start; /* <-- fix the sticky not work issue */ transform: scale(0.9999); /* <-- fix the sticky x overflow issue */ top: 83.84px; }
@media screen and (max-width: 800px) { .framework .sidebar { display: none; } }
/** Segments page */
.page-segments .page-segments-list { margin-left: 0; list-style: none; }
.page-segments .segment-name { font-weight: 600; margin-bottom: 8px; position: relative; font-size: 22.4px; }
.page-segments .segment-name:not(:first-child) { margin-top: 28px; }
.page-segments .segment-name:hover:before { content: '#'; left: -1em; position: absolute; }
.page-segments .post-meta { font-size: 12.25px; color: #828282; }
.page-segments li a { color: #303030; }
.page-segments li a.post-link { margin-left: 5px; }
.page-segments li a:hover { color: #000; }
.page-segments li a:after { content: 'NEW'; position: absolute; margin-left: 8px; margin-top: 3px; padding: 0px 3px; background-color: #ff5100; color: #fff; font-size: 10px; font-weight: 600; border-radius: 2px; }
.page-segments li a:visited:after { background-color: #fff; }
.left-vsplit:before { content: ""; display: inline-block; width: 1px; height: 10px; margin: 0 10px; background-color: #e3e3e3e3; vertical-align: baseline; }
@media screen and (max-width: 800px) { html[data-theme="dark"][data-scroll-status='top'] header.site-header-transparent.site-header .page-link { color: #f8f8f8; } }
html[data-theme="dark"][data-scroll-status='top'] footer.site-footer .site-footer-inner { border-top: solid 1px #2f2f2f !important; transition: 0s; }
html[data-theme="dark"] body { color: #bbb; background-color: #0e0e0e; }
html[data-theme="dark"] *:not(pre) > code { color: #bbb; background-color: #454545; }
html[data-theme="dark"] blockquote { border-left: 4px solid #484848; }
html[data-theme="dark"] table { color: #9d9d9d; }
html[data-theme="dark"] table th { background-color: #050505; }
html[data-theme="dark"] table tr:nth-child(even) { background-color: #080808; }
html[data-theme="dark"] .site-header { background-color: #090909; }
html[data-theme="dark"] .site-header .site-brand .site-brand-inner, html[data-theme="dark"] .site-header .site-brand .site-brand-inner:visited { color: #f8f8f8; }
html[data-theme="dark"] .site-header .site-nav .page-link { color: #f8f8f8; }
html[data-theme="dark"] .site-header .ct-language-dropdown { color: #f8f8f8; background-color: #0e0e0e; box-shadow: 0 0 3px 1px #0000005b; }
html[data-theme="dark"] .site-header .ct-language-selected, .ct-language-dropdown html[data-theme="dark"] .site-header li:hover, html[data-theme="dark"] .site-header .ct-language-dropdown li:hover { background-color: #222 !important; }
@media screen and (max-width: 800px) { html[data-theme="dark"] .site-header .menu-icon > svg { fill: #bbbbbb; } html[data-theme="dark"] .site-header .site-nav input:checked ~ .trigger { background-color: #090909; } }
html[data-theme="dark"] .site-footer { color: #fff; background-color: #000; }
html[data-theme="dark"] .left-vsplit:before { background-color: #9a9a9a; }
html[data-theme="dark"] .page-banner .page-banner-img > *:first-child { opacity: 0.718; }
html[data-theme="dark"] .pagination .post-link { color: #bbb; }
html[data-theme="dark"] .pagination .post-title a:visited:after { background-color: #0e0e0e; }
html[data-theme="dark"] .pagination .post-title a:after { color: #0e0e0e; }
html[data-theme="dark"] .pagination .post-list > li:not(:last-child) { border-bottom: 1px solid #545454; }
html[data-theme="dark"] .pagination .post-tags .post-tag:hover { color: #d7d7d7; }
html[data-theme="dark"] .page-segments li a { color: #ddd; }
html[data-theme="dark"] .page-segments li a:visited:after { background-color: #0e0e0e; }
html[data-theme="dark"] .page-segments li a:after { color: #0e0e0e; }
html[data-theme="dark"] .post .post-content img:not([raw]) { background-color: #ffffff33; }
html[data-theme="dark"] .post-related > *:first-child { color: #d7d7d7; }
html[data-theme="dark"] .post-related a:visited:after { background-color: #0e0e0e; }
html[data-theme="dark"] .post-related a:after { color: #0e0e0e; }
html[data-theme="dark"] .post-related a:hover { color: #aaa; }
html[data-theme="dark"] .common-list li { border-bottom: solid 1px #40404088; }
html[data-theme="dark"] .common-list li a { color: #aaa; }
html[data-theme="dark"] .common-list li a:hover { background-color: #272727; }
html[data-theme="dark"] .common-list li span { background-color: #333; }
html[data-theme="dark"] .post-menu .post-menu-title { color: #ddd; }
html[data-theme="dark"] .post-menu .post-menu-content ul { border-left: 1px solid #787878; }
html[data-theme="dark"] .post-menu .post-menu-content ul .active { background-color: #2d2d2d; border-left: 2px solid #aaa; }
html[data-theme="dark"] .post-menu .post-menu-content ul a { color: #bbb; }
html[data-theme="dark"] .post-menu .post-menu-content ul a:hover { color: #fff !important; }
.theme-toggle { position: relative; width: 107.1px; margin-top: 10px; margin-right: 60px; margin-left: auto; transition: 0.3s cubic-bezier(0.4, 0.03, 0, 1); /* Toggle */ }
.theme-toggle label, .theme-toggle .toggle { border-radius: 100px; }
.theme-toggle label { display: block; background-color: rgba(120, 120, 120, 0.15); cursor: pointer; }
.theme-toggle .toggle { position: absolute; width: 50%; height: 100%; background-color: #fff; box-shadow: 0 2px 15px rgba(0, 0, 0, 0.15); transition: transform 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94); }
.theme-toggle .names { font-size: 1em; font-weight: bolder; width: 76%; margin-left: 12%; position: relative; display: flex; justify-content: space-between; user-select: none; }
.theme-toggle .dark { opacity: .5; }
.theme-toggle p { color: #acacac; margin-bottom: 0; line-height: 24px; }
.theme-toggle [type="checkbox"] { display: none; }
.theme-toggle [type="checkbox"]:checked ~ label .toggle { transform: translateX(100%); background-color: #34323D; }
.theme-toggle [type="checkbox"]:checked ~ label .dark { opacity: 1; }
.theme-toggle [type="checkbox"]:checked ~ label .light { opacity: .5; }
@media screen and (max-width: 1024px) { .theme-toggle { margin-right: 35px; } }
@media screen and (max-width: 600px) { .theme-toggle { width: 93.1px; margin-right: 20px; } .theme-toggle .names { font-size: .85em; } }
/* Post menu */
.post-menu { padding-left: 20px; min-width: 200px; max-width: 230px; }
.post-menu .post-menu-title { font-size: 21px; margin-bottom: 14px; font-weight: 600; color: #222; }
.post-menu .post-menu-content ul { border-left: 1px solid #e9ecef; }
.post-menu .post-menu-content ul .h-h2 { padding-inline-start: 3.5px; font-size: 15.4px; line-height: 1.4; }
.post-menu .post-menu-content ul .h-h3 { padding-inline-start: 21.7px; font-size: 15.4px; line-height: 1.4; }
.post-menu .post-menu-content ul .h-h4 { padding-inline-start: 39.9px; font-size: 15.4px; line-height: 1.4; }
.post-menu .post-menu-content ul .h-h5 { padding-inline-start: 58.1px; font-size: 15.4px; line-height: 1.4; }
.post-menu .post-menu-content ul .h-h6 { padding-inline-start: 76.3px; font-size: 15.4px; line-height: 1.4; }
.post-menu .post-menu-content ul a { display: flex; padding: 2px 8px; color: #2c2c2c; }
.post-menu .post-menu-content ul a * { pointer-events: none; }
.post-menu .post-menu-content ul a:hover { text-decoration: none; color: #787878 !important; }
.post-menu .post-menu-content ul .active { background-color: #ecebec; transition: background 0.5s; border-left: 2px solid #202020; margin-left: -2px; }
.post-menu .post-menu-content ul .active:hover { background-color: #f1f0f1; }
.post-menu .post-menu-content ul .active a { color: #121416; }
/** Common list */
.common-list { font-size: 14px; min-width: 200px; }
.common-list ul { list-style: none; margin: 0; }
.common-list li { border-bottom: solid 1px #00000018; }
.common-list li:last-child { border-bottom: none; }
.common-list li a { display: flex; justify-content: space-between; padding: 8px 12px; text-decoration: none; font-weight: normal; color: #454545; transition: background 0.2s; }
.common-list li a:hover { background-color: #eeeeee; }
.common-list li span { font-size: 11.2px; display: inline-block; border-radius: 10px; align-self: center; background: #000000bd; padding: 0px 8px; margin-left: 20px; color: #fdfdfd; }
/* OVERRIDE GOOGLE TRANSLATE WIDGET CSS BEGIN */
div#google_translate_element div.goog-te-gadget-simple a.goog-te-menu-value { vertical-align: top !important; /* Remove the down arrow */ /* when dropdown open */ /* after clicked/touched */ /* on page load (not yet touched or clicked) */ /* Remove span with left border line | (next to the arrow) in Chrome & Firefox */ /* Remove span with left border line | (next to the arrow) in Edge & IE11 */ }
div#google_translate_element div.goog-te-gadget-simple a.goog-te-menu-value:hover { text-decoration: none; }
div#google_translate_element div.goog-te-gadget-simple a.goog-te-menu-value span { color: #aaa; }
div#google_translate_element div.goog-te-gadget-simple a.goog-te-menu-value span:hover { color: white; }
div#google_translate_element div.goog-te-gadget-simple a.goog-te-menu-value span[style="color: rgb(213, 213, 213);"] { display: none; }
div#google_translate_element div.goog-te-gadget-simple a.goog-te-menu-value span[style="color: rgb(118, 118, 118);"] { display: none; }
div#google_translate_element div.goog-te-gadget-simple a.goog-te-menu-value span[style="color: rgb(155, 155, 155);"] { display: none; }
div#google_translate_element div.goog-te-gadget-simple a.goog-te-menu-value span[style="border-left: 1px solid rgb(187, 187, 187);"] { display: none; }
div#google_translate_element div.goog-te-gadget-simple a.goog-te-menu-value span[style="border-left-color: rgb(187, 187, 187); border-left-width: 1px; border-left-style: solid;"] { display: none; }
div#google_translate_element { display: inline; }
div#google_translate_element div.goog-te-gadget { display: inline; font-size: 0; }
div#google_translate_element div[id=':0.targetLanguage'] { display: inline; }
div#google_translate_element div.goog-te-gadget-simple { border: none; background-color: transparent; }
div#google_translate_element a.goog-logo-link { display: none; }
div#google_translate_element .goog-te-gadget-icon { display: none !important; /*background: url("url for the icon") 0 0 no-repeat !important;*/ }
div#google_translate_element a.goog-te-menu-value { margin: 0; }
div#google_translate_element a.goog-te-menu-value span:first-child { display: none; }
div#google_translate_element a.goog-te-menu-value:before { content: "\f1ab \f0d7"; font-family: FontAwesome; font-size: initial; color: #fefefe; border: 1px solid #fefefe85; border-radius: 3px; padding: 3px 6px; }
.goog-te-menu-frame .goog-te-menu2 { max-width: 100%; overflow-x: auto; box-sizing: border-box; height: auto; }
/* HIDE the google translate toolbar */
.goog-te-banner-frame.skiptranslate { display: none !important; border: none; box-shadow: 0 0; -webkit-box-shadow: 0 0; }
body { top: 0px !important; }
/* OVERRIDE GOOGLE TRANSLATE WIDGET CSS END */
.ct-language-selected, .ct-language-dropdown li:hover { background-color: #f2f2f2 !important; }
.ct-language-dropdown { overflow: hidden; max-height: 0; position: absolute; top: 110%; right: -10px; background-color: white; -webkit-transition: all 0.25s ease-in-out; transition: all 0.25s ease-in-out; width: 100px; text-align: center; margin-top: 0; z-index: 200; border-radius: 3px; visibility: hidden; }
.ct-language-dropdown li { padding: 5px; }
.ct-language-dropdown li:first-child { padding-top: 12px; }
.ct-language-dropdown li:last-child { padding-bottom: 12px; }
.ct-language-dropdown li:not(:last-child) { border-bottom: 1px solid rgba(0, 0, 0, 0.04); }
.ct-language-dropdown li a { display: block; color: black; }
.ct-language-dropdown li a img { width: 24px; max-height: 24px; border: none; }
.list-unstyled { display: inline-block; list-style: none; margin-left: 0; }
.ct-language { display: inline-block; position: relative; background-color: #fefefe2b; padding: 3px 10px; border-radius: 3px; }
.ct-language:hover { cursor: pointer; }
.ct-language:hover .ct-language-dropdown { margin-top: 8px; max-height: 10000px; visibility: visible; box-shadow: 0 0 9px 3px rgba(0, 0, 0, 0.06); }
.ct-language:before { content: "\f1ab \f0d7"; font-family: FontAwesome; }
.gitment-container { color: #787878 !important; }
.gitment-editor-header { background-color: #fefefe; }
.gitment-comment-main, .gitment-editor-main { background-color: #fff; border-radius: 3px !important; }
.gitment-heart-icon { fill: #ff0808; }
.click-to-top { transition: 0.3s; display: flex; align-items: center; justify-content: center; position: fixed; width: 64px; height: 64px; border-radius: 32px; right: 60px; bottom: 48px; background: white; cursor: pointer; opacity: 0; transform: translateY(10px); box-shadow: 0 2px 15px rgba(0, 0, 0, 0.15); font-size: 24px; user-select: none; }
@media screen and (max-width: 1024px) { .click-to-top { width: 48px; height: 48px; border-radius: 24px; right: 35px; font-size: 20px; } }
@media screen and (max-width: 600px) { .click-to-top { width: 36px; height: 36px; border-radius: 18px; right: 20px; font-size: 16px; } }
.click-to-top.show { opacity: 1; transform: translateY(0); }
html[data-theme="dark"] .click-to-top { background: #34323D; }
/*# sourceMappingURL=main.css.map */

32
assets/css/main.css.map Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,38 +0,0 @@
---
# Only the main Sass file needs front matter (the dashes are enough)
---
// Default theme colors
$theme-colors: (
"coolblack": #090a0b,
"spacegrey": #353535,
"snowwhite": #ffffff,
);
// Default brand colors
$brand-colors: (
"orangered": #ff5100,
"greatgold": #f2cb05,
"greenblue": #389092,
);
$theme-name: "{{ site.theme_color }}";
$brand-name: "{{ site.brand_color }}";
$theme-color: map-get($theme-colors, "snowwhite");
$brand-color: map-get($brand-colors, "orangered");
@if map-has-key($theme-colors, $theme-name) {
$theme-color: map-get($theme-colors, $theme-name);
} @else if str-index($theme-name, "#") == 1 {
$theme-color: {{ site.theme_color | default: '#ffffff' }};
}
@if map-has-key($brand-colors, $brand-name) {
$brand-color: map-get($brand-colors, $brand-name);
} @else if str-index($brand-name, "#") == 1 {
$brand-color: {{ site.brand_color | default: '#ff5100' }};
}
$content-width: {{ site.content_width | default: '920px' }};
@import "yat";

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

View file

@ -0,0 +1,853 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="google-translate-customization" content="108d9124921d80c3-80e20d618ff053c8-g4f02ec6f3dba68b7-c">
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>NordVPN - Jste opravdu v takovém nebezpečí? | Matyáš Caras</title>
<meta name="generator" content="Jekyll v4.3.1">
<meta property="og:title" content="NordVPN - Jste opravdu v takovém nebezpečí?">
<meta name="author" content="hernikplays">
<meta property="og:locale" content="en_US">
<meta name="description" content="Pokud sledujete YouTube, určite jste už narazili na nespočet videí, které sponzoruje nějaký poskytovatel tzv. VPN. Většinou se dozvíte něco jako „vaše data jsou v nebezpečí“ a/nebo „použijte naše služby pro zabezpečení vašich dat před hackery“. Toto se samozřejmě netýká jen NordVPN, ale myslím, že ti mají tu nejagresivnější marketingovou strategii snad ze všech. ČÁST I: Kecy Kdo stojí za NordVPN NordVPN vzniklo v roce 2012 jako produkt Toma Okmana, Eimantase Sabaliauskase a Jonase Karklyse. Služba má sloužit jako tzv. Virtual Private Network neboli virtuální soukromá síť. Můžete se tak skrze NordVPN servery připojovat na internet třeba z Německa. Dle zvoleného protokolu je síťový provoz šifrován. NordVPN vlastní společnost Nord Security, která zastřešuje i ostatní produkty značky Nord. Sídlo má ve Velké Británii. Nord Security kromě VPN nabízí i vlastního správce hesel a šifrovaný cloud.">
<meta property="og:description" content="Pokud sledujete YouTube, určite jste už narazili na nespočet videí, které sponzoruje nějaký poskytovatel tzv. VPN. Většinou se dozvíte něco jako „vaše data jsou v nebezpečí“ a/nebo „použijte naše služby pro zabezpečení vašich dat před hackery“. Toto se samozřejmě netýká jen NordVPN, ale myslím, že ti mají tu nejagresivnější marketingovou strategii snad ze všech. ČÁST I: Kecy Kdo stojí za NordVPN NordVPN vzniklo v roce 2012 jako produkt Toma Okmana, Eimantase Sabaliauskase a Jonase Karklyse. Služba má sloužit jako tzv. Virtual Private Network neboli virtuální soukromá síť. Můžete se tak skrze NordVPN servery připojovat na internet třeba z Německa. Dle zvoleného protokolu je síťový provoz šifrován. NordVPN vlastní společnost Nord Security, která zastřešuje i ostatní produkty značky Nord. Sídlo má ve Velké Británii. Nord Security kromě VPN nabízí i vlastního správce hesel a šifrovaný cloud.">
<link rel="canonical" href="https://caras.cafe/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn.html">
<meta property="og:url" content="https://caras.cafe/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn.html">
<meta property="og:site_name" content="Matyáš Caras">
<meta property="og:type" content="article">
<meta property="article:published_time" content="2022-07-19T00:00:00+00:00">
<meta name="twitter:card" content="summary">
<meta property="twitter:title" content="NordVPN - Jste opravdu v takovém nebezpečí?">
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"BlogPosting","author":{"@type":"Person","name":"hernikplays"},"dateModified":"2022-07-19T00:00:00+00:00","datePublished":"2022-07-19T00:00:00+00:00","description":"Pokud sledujete YouTube, určite jste už narazili na nespočet videí, které sponzoruje nějaký poskytovatel tzv. VPN. Většinou se dozvíte něco jako „vaše data jsou v nebezpečí“ a/nebo „použijte naše služby pro zabezpečení vašich dat před hackery“. Toto se samozřejmě netýká jen NordVPN, ale myslím, že ti mají tu nejagresivnější marketingovou strategii snad ze všech. ČÁST I: Kecy Kdo stojí za NordVPN NordVPN vzniklo v roce 2012 jako produkt Toma Okmana, Eimantase Sabaliauskase a Jonase Karklyse. Služba má sloužit jako tzv. Virtual Private Network neboli virtuální soukromá síť. Můžete se tak skrze NordVPN servery připojovat na internet třeba z Německa. Dle zvoleného protokolu je síťový provoz šifrován. NordVPN vlastní společnost Nord Security, která zastřešuje i ostatní produkty značky Nord. Sídlo má ve Velké Británii. Nord Security kromě VPN nabízí i vlastního správce hesel a šifrovaný cloud.","headline":"NordVPN - Jste opravdu v takovém nebezpečí?","mainEntityOfPage":{"@type":"WebPage","@id":"https://caras.cafe/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn.html"},"url":"https://caras.cafe/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn.html"}</script>
<!-- End Jekyll SEO tag -->
<link rel="shortcut icon" href="">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/typeface-noto-sans@0.0.72/index.min.css">
<link rel="stylesheet" href="/assets/css/main.css">
<script src="/assets/js/main.js"></script><link type="application/atom+xml" rel="alternate" href="https://caras.cafe/feed.xml" title="Matyáš Caras">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js"></script>
<!-- and it's easy to individually load additional languages -->
<script charset="UTF-8" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/languages/go.min.js"></script>
<script>
// Init highlight js
document.addEventListener('DOMContentLoaded', function(event) {
var els = document.querySelectorAll('pre code')
function addLangData(block) {
var outer = block.parentElement.parentElement.parentElement;
var lang = block.getAttribute('data-lang');
for (var i = 0; i < outer.classList.length; i++) {
var cls = outer.classList[i];
if (cls.startsWith('language-')) {
lang = cls;
break;
}
}
if (!lang) {
cls = block.getAttribute('class');
lang = cls ? cls.replace('hljs ', '') : '';
}
if (lang.startsWith('language-')) {
lang = lang.substr(9);
}
block.setAttribute('class', 'hljs ' + lang);
block.parentNode.setAttribute('data-lang', lang);
}
function addBadge(block) {
var enabled = ('true' || 'true').toLowerCase();
if (enabled == 'true') {
var pre = block.parentElement;
pre.classList.add('badge');
}
}
function handle(block) {
addLangData(block);
addBadge(block)
hljs.highlightBlock(block);
}
for (var i = 0; i < els.length; i++) {
var el = els[i];
handle(el);
}
});
</script>
<style>
/* code language badge */
pre.badge::before {
content: attr(data-lang);
color: #fff;
background-color: #ff4e00;
padding: 0 .5em;
border-radius: 0 2px;
text-transform: uppercase;
text-align: center;
min-width: 32px;
display: inline-block;
position: absolute;
right: 0;
}
/* fix wrong badge display for firefox browser */
code > table pre::before {
display: none;
}
</style>
</head>
<body>
<header class="site-header " role="banner">
<div class="wrapper">
<div class="site-header-inner">
<span class="site-brand"><a class="site-brand-inner" rel="author" href="/">
<img class="site-favicon" title="Matyáš Caras" src="" onerror="this.style.display='none'">
Matyáš Caras
</a>
</span><nav class="site-nav">
<input type="checkbox" id="nav-trigger" class="nav-trigger">
<label for="nav-trigger">
<span class="menu-icon">
<svg viewbox="0 0 18 15" width="18px" height="15px">
<path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"></path>
</svg>
</span>
</label>
<div class="trigger">
<a class="page-link" href="/about.html">ABOUT</a><a class="page-link" href="/archives.html">ARCHIVES</a><a class="page-link" href="/categories.html">CATEGORIES</a><a class="page-link" href="/">HOME</a><a class="page-link" href="/tags.html">TAGS</a>
</div>
</nav>
</div>
</div>
</header>
<script>
function initHeader() {
var lastScrollY = getScrollPos().y;
var documentElement = document.documentElement;
function storeScrollData() {
var y = getScrollPos().y;var scrollStatus = "";
if (y <= 0) {
scrollStatus = "top";
} else if ((window.innerHeight + y) >= document.body.offsetHeight) {
scrollStatus = "bottom";
} else {
var isScrollDown = (y - lastScrollY > 0) ? true : false;
scrollStatus = isScrollDown ? "down" : "up";
}
lastScrollY = y;
documentElement.setAttribute("data-scroll-status", scrollStatus);
}
window.addEventListener('scroll', function(e) {
storeScrollData();
});
storeScrollData();
}
document.addEventListener('DOMContentLoaded', initHeader);
</script>
<script>
function hashLocate(hashValue) {
hashValue = hashValue.replace(/^.*#h-/, '');
hashValue = decodeURIComponent(hashValue);
var element = document.getElementById(hashValue);
if (!element) {
return;
}
var header = document.querySelector('header.site-header');
var headerRect = header.getBoundingClientRect();
var headerTop = Math.floor(headerRect.top);
var headerHeight = Math.floor(headerRect.height);
var scrollPos = getScrollPos();
var offsetY = element.offsetTop - (headerTop + headerHeight + 20);
if (offsetY == scrollPos.y) {
return;
}
if (headerTop == 0 && offsetY > scrollPos.y) {
offsetY += headerHeight + 2;
} else if (headerTop < 0 && offsetY < scrollPos.y) {
offsetY -= headerHeight - 2;
}
smoothScrollTo(offsetY);
}
// The first event occurred
window.addEventListener('load', function(event) {
if (window.location.hash) {
hashLocate(window.location.hash);
}
});
// The first event occurred
window.addEventListener('click', function(event) {
if (event.target.tagName.toLowerCase() == 'a') {
hashLocate(event.target.getAttribute('href'));
}
});
</script>
<div class="theme-toggle">
<input type="checkbox" id="theme-switch">
<label for="theme-switch">
<div class="toggle"></div>
<div class="names">
<p class="light">Light</p>
<p class="dark">Dark</p>
</div>
</label>
</div>
<script>
(function() {
var sw = document.getElementById('theme-switch');
var html = document.getElementsByTagName('html')[0];
var nightModeOption = ('auto' || 'auto').toLowerCase();
var storage = nightModeOption === 'manual'
? localStorage
: sessionStorage;
var themeData = loadThemeData();
function saveThemeData(data) {
storage.setItem('theme', JSON.stringify(data));
}
function loadThemeData() {
var data = storage.getItem('theme');
try {
data = JSON.parse(data ? data : '');
} catch(e) {
data = { nightShift: undefined, autoToggleAt: 0 };
saveThemeData(data);
}
return data;
}
function handleThemeToggle(nightShift) {
themeData.nightShift = nightShift;
saveThemeData(themeData);
html.dataset.theme = nightShift ? 'dark' : 'light';
setTimeout(function() {
sw.checked = nightShift ? true : false;
}, 50);
}
function autoThemeToggle() {
// Next time point of theme toggle
var now = new Date();
var toggleAt = new Date();
var hours = now.getHours();
var nightShift = hours >= 19 || hours <=7;
if (nightShift) {
if (hours > 7) {
toggleAt.setDate(toggleAt.getDate() + 1);
}
toggleAt.setHours(7);
} else {
toggleAt.setHours(19);
}
toggleAt.setMinutes(0);
toggleAt.setSeconds(0);
toggleAt.setMilliseconds(0)
var delay = toggleAt.getTime() - now.getTime();
// auto toggle theme mode
setTimeout(function() {
handleThemeToggle(!nightShift);
}, delay);
return {
nightShift: nightShift,
toggleAt: toggleAt.getTime()
};
}
// Listen the theme toggle event
sw.addEventListener('change', function(event) {
handleThemeToggle(event.target.checked);
});
if (nightModeOption == 'auto') {
var data = autoThemeToggle();
// Toggle theme by local setting
if (data.toggleAt > themeData.autoToggleAt) {
themeData.autoToggleAt = data.toggleAt;
handleThemeToggle(data.nightShift);
} else {
handleThemeToggle(themeData.nightShift);
}
} else if (nightModeOption == 'manual') {
handleThemeToggle(themeData.nightShift);
} else {
var nightShift = themeData.nightShift;
if (nightShift === undefined) {
nightShift = nightModeOption === 'on';
}
handleThemeToggle(nightShift);
}
})();
</script>
<div id="click-to-top" class="click-to-top">
<i class="fa fa-arrow-up"></i>
</div>
<script>
(function () {
const clickToTop = document.getElementById('click-to-top');
window.addEventListener('scroll', () => {
if (window.scrollY > 100) {
clickToTop.classList.add('show')
}else {
clickToTop.classList.remove('show')
}
});
clickToTop.addEventListener('click', () => {
window.smoothScrollTo(0);
});
})();
</script>
<main class="page-content" aria-label="Content">
<div class="wrapper">
<div class="framework">
<section class="main">
<div class="post">
<section>
<header class="post-header">
<h1 class="post-title p-name" itemprop="name headline">NordVPN - Jste opravdu v takovém nebezpečí?</h1>
<h2 class="post-subtitle">Ale je to špatná služba?</h2>
<p class="post-meta">
<time class="dt-published" datetime="2022-07-19T00:00:00+00:00" itemprop="datePublished"><i class="fa fa-calendar"></i> Jul 19, 2022
</time>
<span class="post-reading-time left-vsplit"><i class="fa fa-clock-o"></i> About 10 mins</span>
</p>
<div class="post-tags">
<a class="post-tag" href="/tags.html#vpn">#vpn</a><a class="post-tag" href="/tags.html#youtube">#youtube</a><a class="post-tag" href="/tags.html#reklamy">#reklamy</a>
</div></header>
<article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">
<div class="post-content e-content" itemprop="articleBody">
<p>Pokud sledujete YouTube, určite jste už narazili na nespočet videí, které sponzoruje nějaký poskytovatel tzv. <strong>VPN</strong>. Většinou se dozvíte něco jako „vaše data jsou v nebezpečí“ a/nebo „použijte naše služby pro zabezpečení vašich dat před hackery“. Toto se samozřejmě netýká <em>jen</em> NordVPN, ale myslím, že ti mají tu nejagresivnější marketingovou strategii snad ze všech.</p>
<h1 id="část-i-kecy">ČÁST I: Kecy</h1>
<h2 id="kdo-stojí-za-nordvpn">Kdo stojí za NordVPN</h2>
<p>NordVPN vzniklo v roce 2012 jako produkt Toma Okmana, Eimantase Sabaliauskase a Jonase Karklyse. Služba má sloužit jako tzv. <strong>Virtual Private Network</strong> neboli virtuální soukromá síť. Můžete se tak skrze NordVPN servery připojovat na internet třeba z Německa. Dle zvoleného protokolu je síťový provoz šifrován. NordVPN vlastní společnost <a href="https://nordsecurity.com/">Nord Security</a>, která zastřešuje i ostatní produkty značky Nord. Sídlo má ve Velké Británii. Nord Security kromě VPN nabízí i vlastního správce hesel a šifrovaný cloud.</p>
<h2 id="nordvpn-a-reklamy-youtuberů">NordVPN a reklamy YouTuberů</h2>
<p>Reklamy uvnitř obsahu, tedy reklamy, které tvůrce přidává přímo do videa výměnou za přímou platbu od společnosti, jsou tu s námi celkem dlouho. Jsou <strong>efektivnější</strong> než běžné reklamy, protože je s běžným blokovačem reklam nepřeskočíte a často je tvůrci tvoří zábavným způsobem, aby je sledující sám nepřeskočil. Je to <strong>stabilnější příjem</strong> pro tvůrce obsahu, jelikož se nemusí spoléhat na výdělek z reklam, které YouTube často omezuje svými pravidli demonetizace. To je také jeden z důvodů, proč často youtubeři těmto druhům reklam vyjdou vstříc, i když nemusí mít o daném produktu žádnou znalost. Často tak ve svých videích poskytují nepravdivé či přímo zavádějící tvrzení. Než uvedu příklady, je nutné si uvědomit, že <strong>ne každý takový YouTuber poskytuje zavádějící informace</strong> nebo že <strong>NordVPN nejsou žádní podvodníci</strong>. Nejsem žádný „samozvaný IT expert“, takže mě neváhejte případně opravit. A o tvrzení „NordVPN je nejlepší VPN“ se bavit ani nebudu, o tom si udělejte obrázek sami.</p>
<h3 id="tvrzení-č-1">Tvrzení č. 1:</h3>
<p><strong><a href="https://youtu.be/51TNTCAD8fQ?t=68">Veřejné WiFi jsou nebezpečné a kdokoliv může sledovat, co na nich děláte</a></strong></p>
<p>Zalíbila se mi <a href="https://www.quora.com/Is-it-safe-to-use-internet-from-open-public-WiFi-hotspots/answer/Scott-Helms-8">odpověď Scotta Helmse</a>, který přirovnává veřejné WiFi sítě k veřejným ulicím. Pokud budete dělat hlouposti, jako je chození s přilepenou platební kartou na čele, samozřejmě vaše údaje budou odcizeny. Proto určitě není dobrý nápad dělat nákupy či se přihlašovat do bankovnictví skrz veřejné sítě. Když se na to podíváme realisticky, je relativně malá šance, že si zrovna k vám v mekáči sedl chlapec či dívka s laptopem, na kterém projíždí vaši historii vyhledávání. Navíc většina webů je zabezpečená pomocí SSL, takže přenos dat je šifrovaný. Takže při používání VPN to vlastně šifrujete ještě jednou (?), což už ale tak užitečné není. Jak <a href="https://www.eff.org/deeplinks/2020/01/why-public-wi-fi-lot-safer-you-think">píše</a> EFF, tyto hrozby jsou díky HTTPS/SSL spíše minulostí. Váš poskytovatel internetu může sledovat např. jakou stránku otevíráte (třeba github.com), nicméně neuvidí žádné parametry, které odesíláte, ani jestli navštěvujete github.com/hernikplays nebo github.com/ytdl. A to stejné mohou lidé, kteří jsou kolem vás připojení na veřejné WiFi. „V životě se bojíte spousty věcí, veřejné WiFi si můžete ze seznamu odškrtnout“.</p>
<h3 id="tvrzení-č-2">Tvrzení č. 2:</h3>
<p><strong><a href="https://youtu.be/a_LiGXtXXNQ?t=1642">[NordVPN poskytuje] maximální internetové bezpečí</a></strong></p>
<p>Jak už jsem řekl v předchozí části, před vlastní blbostí vás ani to nejlepší VPN nezachrání. Pokud máte selský rozum, tak poznáte, kam zadávat a nezadávat svoje osobní údaje, což se s rostoucí popularitou sociálního inženýrství o něco zhoršuje. A pokud si vás přecijen nějaký špičkový, státem placený hacker najde, tak mu VPN určitě nebude dělat problém.</p>
<h3 id="tvrzení-č-3">Tvrzení č. 3:</h3>
<p><strong><a href="https://youtu.be/sB8vHDS1Tcg?t=380">Zatímco [bez VPN] ti může jakýkoliv útočník vcelku jednoduše tvé zařízení nabourat, s ním jsi prakticky neviditelný […] smaže za tebou tvou stopu</a></strong></p>
<p>Toto tvrzení je možná pravdivé pro NordVPN, jelikož nabízejí službu „<a href="https://nordvpn.com/features/threat-protection/">Threat Protection</a>“, která slouží k blokování reklam, sledovacích prvků a nebezpečných webů, nicméně může vzbudit dojem, že takhle operuje každé VPN. Pokud vám jde o vaše bezpečí, neměli byste sázet na řešení jedním kliknutím, ale <a href="https://mullvad.net/en/help/first-steps-towards-online-privacy/">prozkoumat různé možnosti a nástroje</a>, včetně VPN. Pokud používáte např. služby od Googlu, už tak jim o sobě poskytujete dostatek údajů.
Útočník také nemůže „vcelku jednoduše“ vaše zařízení nabourat, to lze pouze pokud jste se rozhodli používat Windows 10 a nenainstalovali jste žádné aktualizace. V tom případě je váš systém děravý jak ementál a to už asi nikdo, kromě vás, nespraví. Takže aktualizujte svůj systém a aplikace jak to jen půjde!</p>
<h3 id="tvrzení-č-4">Tvrzení č. 4:</h3>
<p><strong>Můžeš sledovat obsah uzamknutý pro určité země</strong></p>
<p>To je samozřejmě pravda, nicméně některé služby se aktivně pokouší zamezit přístup uživatelům s VPN identifikováním IP adresy daného VPN serveru.</p>
<h3 id="tvrzení-č-5">Tvrzení č. 5:</h3>
<p><strong><a href="https://youtu.be/sB8vHDS1Tcg?t=436">[NordVPN] ti zrychlí internet</a></strong></p>
<p>Když máte od poskytovatele internetu omezené stahování na 10 MB/s, nemůžete očekávat, že když budete ze serveru, kde může být zároveň napojeno X tisíc lidí a je někde v tramtárii, stahovat soubor, že se bude stahovat rychleji. <a href="https://www.cloudflare.com/learning/access-management/vpn-speed/">Pouze ve specifických případech</a>, kdy například poskytovatel internetu záměrně zpomaluje připojení např. k Netflixu, můžete pocítit zrychlení.</p>
<h2 id="nordvpn-a-ještě-divnější-praktiky">NordVPN a ještě divnější praktiky</h2>
<p>Zavádějícími tvrzeními to však nekončí, věděli jste, že na mnoha webech s hodnoceními VPN služeb si můžete určitou pozici <strong>jednoduše koupit</strong>? Ano, dostáváme se do takzvaného <strong>provizního systému</strong>, tedy systému, ve kterém firma proplatí provizi z provedeného nákupu jistému zprostředkovateli. Vtipná věc je, že některé tyto firmy <a href="https://blog.windscribe.com/consolidation-of-the-vpn-industry-spells-trouble-for-the-consumer-57e638634cf0/">vlastní</a> zároveň takovéto <em>„publikace“</em> a samotné VPN služby, jako např. Kape Technologies, která se původně <strong>zabývala adwarem</strong>, nyní vlastní např. ExpressVPN a zároveň web VPNmentor. NordVPN není výjimkou s jejich provizním systémem nabízejícím až 40% část z ceny nákupu. Dá se těmto „hodnocením“ vůbec věřit? Některým nejspíš ano, je dobré však zkontrolovat, jestli publikaci nevlastní nějaká mediální společnost.</p>
<p>Dále můžeme na webu NordVPN, služby, která vám má pomoct chránit vaše soukromí a <em>„zneviditelnit se“</em>, <strong>najít spoustu sledovacích prvků</strong>, jako např. sledovací prvky Twitter Ads, Google Ads, Analytics a Bing.</p>
<p><img src="/assets/images/vpn/14.png" alt="Ukázka sledovacích prvků na stránce NordVPN"></p>
<h1 id="část-ii-vzhůru-dolů">Část II: Vzhůru dolů</h1>
<p>Ano, je čas, abych se vydal do králičí nory a NordVPN otestoval. Hned na úvodní stránce na vás vyskočí tuny slev. „Nakupte do X hodin a získejte slevu X%“. No tak to abych si pohnul, co? Samozřejmě, že ne. Úplně stejná stránka s úplně stejným odpočtem se mi zobrazila i včera. Navíc tato sleva platí jen na roční plány a já s NordVPN chci strávit co nejméně času. Takže beru jejich standardních 10,49 eur na měsíc, které naštěstí také nabízejí s garancí vrácení peněz. Samozřejmě k tomu ještě musíte přičíst daně, z čehož máme 12,69 <em>(nice)</em>. Použil jsem jejich <a href="https://www.theregister.com/2020/03/06/nordvpn_no_auth_needed_view_user_payments/">(ne)</a>bezpečnou bránu a vzdal se svých těžce vydělaných peněz.
Jejich stránka, ze které jsem měl stáhnout klienta, se chvástala „online zabezpečením pro všechny velké linuxové distribuce“, takže je super, že nabízejí stažení pouze pro distribuce založené na Debianu a RHEL, když jsem na Archu. Samozřejmě nic, co by Arch komunita nevyřešila.</p>
<p>Nemůžu hodnotit jednoduchost prostředí, protože <em>to na linuxu ani není</em>. Nicméně se podíváme na rychlost.</p>
<h2 id="rychlosti-velmi-stručně">Rychlosti (velmi stručně)</h2>
<p><img src="/assets/images/vpn/13.png" alt="Výchozí rychlost (bez VPN, WiFi)"></p>
<p>Výchozí rychlost (bez VPN, WiFi)</p>
<p><img src="/assets/images/vpn/12.png" alt="NordVPN Germany #1078"></p>
<p>NordVPN Germany #1078</p>
<p><img src="/assets/images/vpn/11.png" alt="Rychlost stahování torrentů na serverech v Německu"></p>
<p>Pokles rychlosti, úplně normální, protože pakety urazí větší vzdálenost. Streamování YouTube ve Full HD má pocititelné zpomalení/zasekávání. Rychlosti stahování torrentů se držely v průměru mezi 600 a 700 KB/s.</p>
<p><img src="/assets/images/vpn/10.png" alt="NordVPN USA #9363"></p>
<p>NordVPN USA #9363</p>
<p><img src="/assets/images/vpn/9.png" alt="Rychlost stahování torrentů na serverech v USA"></p>
<p>Tady už změnu pocítíte víc. Zajímavé však je, že se videa z YouTube ve Full HD načítají rychleji. Nicméně rychlosti stahování torrentů skákaly nahorů a dolů.</p>
<h2 id="threat-protection-lite">Threat Protection Lite</h2>
<p>Další funkce dostupná pro linux je <a href="https://support.nordvpn.com/General-info/Features/1047407402/What-are-Threat-Protection-and-Threat-Protection-Lite.htm">TPL</a>, který má blokovat reklamy, nebezpečné stránky a pochybná připojení během připojení na VPN.</p>
<p>Na webu NordVPN zablokoval sledovací prvky Twitteru, Bingu a Googlu, nicméně vynechal Google Analytics (což je asi pochopitelné, když o blokování sledujících prvků není ani zmínka).</p>
<p><img src="/assets/images/vpn/8.png" alt="Zablokované sledovací prvky na NordVPN.com"></p>
<p>Na YouTube neblokuje reklamy vůbec,
<img src="/assets/images/vpn/7.png" alt="Blokování reklam s TPL na YouTube"></p>
<p>ale na jiných webech ano.
<img src="/assets/images/vpn/6.png" alt="Blokování reklam s TPL na jiných webech"></p>
<p>Takže nahradí blokovače jako <a href="https://github.com/gorhill/uBlock#readme">uBlock Origin</a>? Řekl bych, že ne.</p>
<h1 id="část-iii-opouštíme-králičí-noru">Část III: Opouštíme králičí noru</h1>
<p>Dobře, mám trochu NordVPN na vlastní kůži, ale teď se ho chci zbavit. Takže jdeme žádat zpět peníze.
Zrušení obnovení předplatného bylo relativně snadné, v nastavení účtu stačilo kliknout na „Zrušit“.</p>
<p><img src="/assets/images/vpn/5.png" alt="Zrušení obnovení předplatného"></p>
<p>Teď přijde ta bolestivější část, a to žádání o vrácení peněz. Dle podmínek máte 30 dní od prvního nákupu nárok na vrácení peněz.
NordVPN říká, že podpora funguje 24/7. Na začátku jste spojeni s robotem, který vás postupně přepojí na živého člověka.</p>
<p><img src="/assets/images/vpn/4.png" alt="Robot na podpoře"></p>
<p>Člověk se skutečně objevil.</p>
<p><img src="/assets/images/vpn/3.png" alt="Chat s podporu část 1"></p>
<p>Chvilku mu to trvalo, takže jsem ho popostrčil.</p>
<p><img src="/assets/images/vpn/2.png" alt="Chat s podporu část 2"></p>
<p>Řekl jsem mu slušně „Ne, díky“, po čemž mi nastavil vrácení peněz.</p>
<p><img src="/assets/images/vpn/1.png" alt="Chat s podporu část 3"></p>
<p>Celkem rychle vyřízeno, dobrá práce. Zvláštní mi přišlo jen, že si mě nijak neověřil, pouze jsem na začátku poskytl e-mail, z čehož (doufám) vydedukoval, že to patří k mému účtu.
Další den mi skutečně odebrali přístup k jejich službě, nicméně peníze jsou stále zablokované, tak snad si banka pohne.</p>
<h1 id="část-v-závěr">Část V: Závěr</h1>
<p>Takže na závěr:
<strong>Je VPN úplně zbytečný nástroj?</strong> Určitě ne.</p>
<p><strong>Můžou youtubeři za to, že někdy neříkají pravdivé věci?</strong> Spíš ne, nemůžete čekat každého youtubera, že je expert přes sítě, jenom se snaží se uživit a vyloženě lži říkají opravdu málokdy.</p>
<p><strong>Snaží se NordVPN prodat hadí olej a moje děti na darknetu?</strong> Nejspíš ne, ale měli by víc sjednotit prezentování co se týče sponzorování youtuberů.</p>
<p><strong>Můžu důvěřovat NordVPN?</strong> S jejich velikostí nejspíš ano.</p>
<p><strong>Doporučil bych NordVPN?</strong> Ne. Pokud chcete opravdu 100% anonymitu a hlavně no-bullshit produkt, použijte něco jako Mullvad <em>(toto není sponzorováno, sám ho používám a je fajn)</em>, který nenabízí žádné posrané slevy kvůli všemu možnému a kde dokonce můžete platit v hotovosti, ale nezapomeňte, že VPNkem to nekončí. Podívejte se na <a href="https://ssd.eff.org/">Surveillance Self-Defense</a> od EFF pro více tipů na ochranu vašeho soukromí.</p>
</div>
</article>
<div class="post-nav">
<a class="previous" href="/vychyt%C3%A1vky/2022/05/31/codespaces.html" title="GitHub Codespaces aneb VS Code na VPS">GitHub Codespaces aneb VS Code na...</a><a class="next" href="/tutori%C3%A1l/2022/10/22/rpi-arch.html" title="Instalujeme Arch Linux ARM na Raspberry Pi 3">Instalujeme Arch Linux ARM na Raspberry...</a>
</div>
<div class="post-related">
<div>Related Articles</div>
<ul>
<li><a class="post-link" href="/vychyt%C3%A1vky/2022/05/31/codespaces.html" title="Instalujeme Arch Linux ARM na Raspberry Pi 3">GitHub Codespaces aneb VS Code na VPS</a></li>
<li><a class="post-link" href="/programov%C3%A1n%C3%AD/2022/05/22/automatizace.html" title="Instalujeme Arch Linux ARM na Raspberry Pi 3">Automatizace, automatizace, automatizace</a></li>
<li><a class="post-link" href="/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn.html" title="Instalujeme Arch Linux ARM na Raspberry Pi 3">NordVPN - Jste opravdu v takovém nebezpečí?</a></li>
<li><a class="post-link" href="/tutori%C3%A1l/2022/10/22/rpi-arch.html" title="Instalujeme Arch Linux ARM na Raspberry Pi 3">Instalujeme Arch Linux ARM na Raspberry Pi 3</a></li>
</ul>
</div>
<div class="post-comments"> <div id="gitment_thread" class="giscus"></div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/theme-next/theme-next-gitment@1/default.css">
<script src="https://cdn.jsdelivr.net/gh/theme-next/theme-next-gitment@1/gitment.browser.js"></script>
<script src="https://giscus.app/client.js" data-repo="hernikplays/blog" data-repo-id="R_kgDOHr2B6w" data-category="General" data-category-id="DIC_kwDOHr2B684CSIhA" data-mapping="pathname" data-strict="0" data-reactions-enabled="1" data-emit-metadata="0" data-input-position="top" data-theme="transparent_dark" data-lang="en" data-loading="lazy" crossorigin="anonymous" async>
</script>
</div></section>
</div>
</section>
<section class="sidebar" style="margin-left: 15px;">
<!-- Get sidebar items --></section>
</div>
</div>
</main><footer class="site-footer h-card">
<data class="u-url" href="/"></data>
<div class="wrapper">
<div class="site-footer-inner">
<div>Copyright © 2021-2022 hernikplays</div>
<div>Powered by <a title="Jekyll is a simple, blog-aware, static site
generator." href="https://jekyllrb.com/">Jekyll</a> &amp; <a title="Yat, yet
another theme." href="https://github.com/jeffreytse/jekyll-theme-yat">Yat Theme</a>.</div>
<div><a rel="me" href="https://social.linux.pizza/@hernik">Mastodon</a></div>
<div class="footer-col rss-subscribe">Subscribe <a href="/feed.xml">via RSS</a>
</div>
</div>
</div>
</footer>
</body>
</html>

View file

@ -1,4 +1,789 @@
---
layout: categories
title: Categories
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="google-translate-customization" content="108d9124921d80c3-80e20d618ff053c8-g4f02ec6f3dba68b7-c">
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>Categories | Matyáš Caras</title>
<meta name="generator" content="Jekyll v4.3.1">
<meta property="og:title" content="Categories">
<meta name="author" content="hernikplays">
<meta property="og:locale" content="en_US">
<meta name="description" content="Welcome to my website/blog, full of weird stuff written by yours truly.">
<meta property="og:description" content="Welcome to my website/blog, full of weird stuff written by yours truly.">
<link rel="canonical" href="https://caras.cafe/categories.html">
<meta property="og:url" content="https://caras.cafe/categories.html">
<meta property="og:site_name" content="Matyáš Caras">
<meta property="og:type" content="website">
<meta name="twitter:card" content="summary">
<meta property="twitter:title" content="Categories">
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"WebPage","author":{"@type":"Person","name":"hernikplays"},"description":"Welcome to my website/blog, full of weird stuff written by yours truly.","headline":"Categories","url":"https://caras.cafe/categories.html"}</script>
<!-- End Jekyll SEO tag -->
<link rel="shortcut icon" href="">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/typeface-noto-sans@0.0.72/index.min.css">
<link rel="stylesheet" href="/assets/css/main.css">
<script src="/assets/js/main.js"></script><link type="application/atom+xml" rel="alternate" href="https://caras.cafe/feed.xml" title="Matyáš Caras">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js"></script>
<!-- and it's easy to individually load additional languages -->
<script charset="UTF-8" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/languages/go.min.js"></script>
<script>
// Init highlight js
document.addEventListener('DOMContentLoaded', function(event) {
var els = document.querySelectorAll('pre code')
function addLangData(block) {
var outer = block.parentElement.parentElement.parentElement;
var lang = block.getAttribute('data-lang');
for (var i = 0; i < outer.classList.length; i++) {
var cls = outer.classList[i];
if (cls.startsWith('language-')) {
lang = cls;
break;
}
}
if (!lang) {
cls = block.getAttribute('class');
lang = cls ? cls.replace('hljs ', '') : '';
}
if (lang.startsWith('language-')) {
lang = lang.substr(9);
}
block.setAttribute('class', 'hljs ' + lang);
block.parentNode.setAttribute('data-lang', lang);
}
function addBadge(block) {
var enabled = ('true' || 'true').toLowerCase();
if (enabled == 'true') {
var pre = block.parentElement;
pre.classList.add('badge');
}
}
function handle(block) {
addLangData(block);
addBadge(block)
hljs.highlightBlock(block);
}
for (var i = 0; i < els.length; i++) {
var el = els[i];
handle(el);
}
});
</script>
<style>
/* code language badge */
pre.badge::before {
content: attr(data-lang);
color: #fff;
background-color: #ff4e00;
padding: 0 .5em;
border-radius: 0 2px;
text-transform: uppercase;
text-align: center;
min-width: 32px;
display: inline-block;
position: absolute;
right: 0;
}
/* fix wrong badge display for firefox browser */
code > table pre::before {
display: none;
}
</style>
</head>
<body>
<header class="site-header " role="banner">
<div class="wrapper">
<div class="site-header-inner">
<span class="site-brand"><a class="site-brand-inner" rel="author" href="/">
<img class="site-favicon" title="Matyáš Caras" src="" onerror="this.style.display='none'">
Matyáš Caras
</a>
</span><nav class="site-nav">
<input type="checkbox" id="nav-trigger" class="nav-trigger">
<label for="nav-trigger">
<span class="menu-icon">
<svg viewbox="0 0 18 15" width="18px" height="15px">
<path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"></path>
</svg>
</span>
</label>
<div class="trigger">
<a class="page-link" href="/about.html">ABOUT</a><a class="page-link" href="/archives.html">ARCHIVES</a><a class="page-link" href="/categories.html">CATEGORIES</a><a class="page-link" href="/">HOME</a><a class="page-link" href="/tags.html">TAGS</a>
</div>
</nav>
</div>
</div>
</header>
<script>
function initHeader() {
var lastScrollY = getScrollPos().y;
var documentElement = document.documentElement;
function storeScrollData() {
var y = getScrollPos().y;var scrollStatus = "";
if (y <= 0) {
scrollStatus = "top";
} else if ((window.innerHeight + y) >= document.body.offsetHeight) {
scrollStatus = "bottom";
} else {
var isScrollDown = (y - lastScrollY > 0) ? true : false;
scrollStatus = isScrollDown ? "down" : "up";
}
lastScrollY = y;
documentElement.setAttribute("data-scroll-status", scrollStatus);
}
window.addEventListener('scroll', function(e) {
storeScrollData();
});
storeScrollData();
}
document.addEventListener('DOMContentLoaded', initHeader);
</script>
<script>
function hashLocate(hashValue) {
hashValue = hashValue.replace(/^.*#h-/, '');
hashValue = decodeURIComponent(hashValue);
var element = document.getElementById(hashValue);
if (!element) {
return;
}
var header = document.querySelector('header.site-header');
var headerRect = header.getBoundingClientRect();
var headerTop = Math.floor(headerRect.top);
var headerHeight = Math.floor(headerRect.height);
var scrollPos = getScrollPos();
var offsetY = element.offsetTop - (headerTop + headerHeight + 20);
if (offsetY == scrollPos.y) {
return;
}
if (headerTop == 0 && offsetY > scrollPos.y) {
offsetY += headerHeight + 2;
} else if (headerTop < 0 && offsetY < scrollPos.y) {
offsetY -= headerHeight - 2;
}
smoothScrollTo(offsetY);
}
// The first event occurred
window.addEventListener('load', function(event) {
if (window.location.hash) {
hashLocate(window.location.hash);
}
});
// The first event occurred
window.addEventListener('click', function(event) {
if (event.target.tagName.toLowerCase() == 'a') {
hashLocate(event.target.getAttribute('href'));
}
});
</script>
<div class="theme-toggle">
<input type="checkbox" id="theme-switch">
<label for="theme-switch">
<div class="toggle"></div>
<div class="names">
<p class="light">Light</p>
<p class="dark">Dark</p>
</div>
</label>
</div>
<script>
(function() {
var sw = document.getElementById('theme-switch');
var html = document.getElementsByTagName('html')[0];
var nightModeOption = ('auto' || 'auto').toLowerCase();
var storage = nightModeOption === 'manual'
? localStorage
: sessionStorage;
var themeData = loadThemeData();
function saveThemeData(data) {
storage.setItem('theme', JSON.stringify(data));
}
function loadThemeData() {
var data = storage.getItem('theme');
try {
data = JSON.parse(data ? data : '');
} catch(e) {
data = { nightShift: undefined, autoToggleAt: 0 };
saveThemeData(data);
}
return data;
}
function handleThemeToggle(nightShift) {
themeData.nightShift = nightShift;
saveThemeData(themeData);
html.dataset.theme = nightShift ? 'dark' : 'light';
setTimeout(function() {
sw.checked = nightShift ? true : false;
}, 50);
}
function autoThemeToggle() {
// Next time point of theme toggle
var now = new Date();
var toggleAt = new Date();
var hours = now.getHours();
var nightShift = hours >= 19 || hours <=7;
if (nightShift) {
if (hours > 7) {
toggleAt.setDate(toggleAt.getDate() + 1);
}
toggleAt.setHours(7);
} else {
toggleAt.setHours(19);
}
toggleAt.setMinutes(0);
toggleAt.setSeconds(0);
toggleAt.setMilliseconds(0)
var delay = toggleAt.getTime() - now.getTime();
// auto toggle theme mode
setTimeout(function() {
handleThemeToggle(!nightShift);
}, delay);
return {
nightShift: nightShift,
toggleAt: toggleAt.getTime()
};
}
// Listen the theme toggle event
sw.addEventListener('change', function(event) {
handleThemeToggle(event.target.checked);
});
if (nightModeOption == 'auto') {
var data = autoThemeToggle();
// Toggle theme by local setting
if (data.toggleAt > themeData.autoToggleAt) {
themeData.autoToggleAt = data.toggleAt;
handleThemeToggle(data.nightShift);
} else {
handleThemeToggle(themeData.nightShift);
}
} else if (nightModeOption == 'manual') {
handleThemeToggle(themeData.nightShift);
} else {
var nightShift = themeData.nightShift;
if (nightShift === undefined) {
nightShift = nightModeOption === 'on';
}
handleThemeToggle(nightShift);
}
})();
</script>
<div id="click-to-top" class="click-to-top">
<i class="fa fa-arrow-up"></i>
</div>
<script>
(function () {
const clickToTop = document.getElementById('click-to-top');
window.addEventListener('scroll', () => {
if (window.scrollY > 100) {
clickToTop.classList.add('show')
}else {
clickToTop.classList.remove('show')
}
});
clickToTop.addEventListener('click', () => {
window.smoothScrollTo(0);
});
})();
</script>
<main class="page-content" aria-label="Content">
<div class="wrapper">
<div class="framework">
<section class="main">
<div class="page-segments">
<ul class="page-segments-list">
<h2 id="bezpečí" class="segment-name">bezpečí</h2>
<li>
<span class="post-meta">Jul 19, 2022</span>
<span>
<a class="post-link" href="/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn.html">
NordVPN - Jste opravdu v takovém nebezpečí?
</a>
</span>
</li>
<h2 id="programování" class="segment-name">programování</h2>
<li>
<span class="post-meta">May 22, 2022</span>
<span>
<a class="post-link" href="/programov%C3%A1n%C3%AD/2022/05/22/automatizace.html">
Automatizace, automatizace, automatizace
</a>
</span>
</li>
<h2 id="tutoriál" class="segment-name">tutoriál</h2>
<li>
<span class="post-meta">Oct 22, 2022</span>
<span>
<a class="post-link" href="/tutori%C3%A1l/2022/10/22/rpi-arch.html">
Instalujeme Arch Linux ARM na Raspberry Pi 3
</a>
</span>
</li>
<h2 id="vychytávky" class="segment-name">vychytávky</h2>
<li>
<span class="post-meta">May 31, 2022</span>
<span>
<a class="post-link" href="/vychyt%C3%A1vky/2022/05/31/codespaces.html">
GitHub Codespaces aneb VS Code na VPS
</a>
</span>
</li>
</ul>
</div>
</section>
<section class="sidebar" style="margin-left: 15px;">
<!-- Get sidebar items -->
<div class="common-list">
<ul>
<li>
<a href="/index.html">
All<span>4</span>
</a>
</li>
<li>
<a href="/categories.html#h-bezpe%C4%8D%C3%AD">
bezpečí <span>1</span>
</a>
</li>
<li>
<a href="/categories.html#h-programov%C3%A1n%C3%AD">
programování <span>1</span>
</a>
</li>
<li>
<a href="/categories.html#h-tutori%C3%A1l">
tutoriál <span>1</span>
</a>
</li>
<li>
<a href="/categories.html#h-vychyt%C3%A1vky">
vychytávky <span>1</span>
</a>
</li>
</ul>
</div>
</section>
</div>
</div>
</main><footer class="site-footer h-card">
<data class="u-url" href="/"></data>
<div class="wrapper">
<div class="site-footer-inner">
<div>Copyright © 2021-2022 hernikplays</div>
<div>Powered by <a title="Jekyll is a simple, blog-aware, static site
generator." href="https://jekyllrb.com/">Jekyll</a> &amp; <a title="Yat, yet
another theme." href="https://github.com/jeffreytse/jekyll-theme-yat">Yat Theme</a>.</div>
<div><a rel="me" href="https://social.linux.pizza/@hernik">Mastodon</a></div>
<div class="footer-col rss-subscribe">Subscribe <a href="/feed.xml">via RSS</a>
</div>
</div>
</div>
</footer>
</body>
</html>

247
feed.xml Normal file
View file

@ -0,0 +1,247 @@
<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.1">Jekyll</generator><link href="https://caras.cafe/feed.xml" rel="self" type="application/atom+xml" /><link href="https://caras.cafe/" rel="alternate" type="text/html" /><updated>2022-11-05T11:35:48+00:00</updated><id>https://caras.cafe/feed.xml</id><title type="html">Matyáš Caras</title><subtitle>Welcome to my website/blog, full of weird stuff written by yours truly.</subtitle><author><name>hernikplays</name></author><entry><title type="html">Instalujeme Arch Linux ARM na Raspberry Pi 3</title><link href="https://caras.cafe/tutori%C3%A1l/2022/10/22/rpi-arch.html" rel="alternate" type="text/html" title="Instalujeme Arch Linux ARM na Raspberry Pi 3" /><published>2022-10-22T00:00:00+00:00</published><updated>2022-10-22T00:00:00+00:00</updated><id>https://caras.cafe/tutori%C3%A1l/2022/10/22/rpi-arch</id><content type="html" xml:base="https://caras.cafe/tutori%C3%A1l/2022/10/22/rpi-arch.html"><![CDATA[<p><img src="https://archlinuxarm.org/public/images/alarm.png" alt="Arch Linux ARM logo" /></p>
<p>Raspbian OS už je ohraný. Pojďme si nainstalovat <a href="https://archlinuxarm.org/platforms/armv8/broadcom/raspberry-pi-3">ARM verzi Arch Linuxu</a> na Raspberry Pi 3. Proces je relativně prostý.</p>
<h1 id="připravujeme-sd-kartu">Připravujeme SD kartu</h1>
<p>Nejdřív je nutné SD kartu naformátovat a rozdělit oddíly. Můžete to udělat svým oblíbeným způsobem, já použiji GUI nástroj GParted.</p>
<p>Odstraníme všechny oddíly skrz kontextové menu pravého kliknutí a potvrzení fajfkou.</p>
<p><img src="/assets/images/rpi-arch/01.png" alt="Odstraněné oddíly v GParted" /></p>
<p>Následně vytvoříme jeden FAT32 oddíl, který bude sloužit jako bootovací. Bude stačit 128 MiB.</p>
<p><img src="/assets/images/rpi-arch/02.png" alt="Vytváření FAT32 oddílu v GParted" /></p>
<p>Druhý oddíl bude náš systémový, který bude ext4.</p>
<p><img src="/assets/images/rpi-arch/03.png" alt="Vytváření ext4 oddílu v GParted" /></p>
<p>Jakmile fajfkou potvrdíme a necháme oddíly vytvořit, můžete je ještě zformátovat, nicméně je nejdůležitější nastavit <code class="language-plaintext highlighter-rouge">boot</code> příznak na našem boot oddílu skrz kontextové menu.</p>
<p><img src="/assets/images/rpi-arch/04.png" alt="Výběr příznaků v GParted" /></p>
<p>Tak je všechno hotovo v GParted.</p>
<h1 id="přesouváme-systém">Přesouváme systém</h1>
<p>Dále připojíme naše oddíly podle jejich identifikátoru a čísla připojíme.</p>
<p>Nejdřív si vytvoříme složky, <code class="language-plaintext highlighter-rouge">sudo mkdir -p /mnt/archpi/{root,boot}</code> nám vytvoří složky <code class="language-plaintext highlighter-rouge">root</code> a <code class="language-plaintext highlighter-rouge">boot</code> pro naše oddíly.</p>
<p>Dále příkazem <code class="language-plaintext highlighter-rouge">sudo mount /dev/sdc1 /mnt/archpi/root</code> připojíme náš FAT32 bootovácí oddíl (<strong>Označení <code class="language-plaintext highlighter-rouge">sdc1</code> se u vás může lišit, podívejte se do GPartedu nebo skrz příkaz <code class="language-plaintext highlighter-rouge">lsblk</code> na označení jednotlivých oddílů</strong>) a příkazem <code class="language-plaintext highlighter-rouge">sudo mount /dev/sdc2 /mnt/archpi/boot</code> připojíme systémový oddíl.</p>
<p>Dle oficiální <a href="https://archlinuxarm.org/platforms/armv8/broadcom/raspberry-pi-3">dokumentace</a> se další proces má dělat skrz root uživatele, takže se přepneme příkazem <code class="language-plaintext highlighter-rouge">sudo su</code>.</p>
<p>Příkazem <code class="language-plaintext highlighter-rouge">wget http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-armv7-latest.tar.gz</code> stáhneme archiv a příkazem <code class="language-plaintext highlighter-rouge">tar -xf ArchLinuxARM-rpi-armv7-latest.tar.gz -C /mnt/archpi/root</code> ho rozbalíme.</p>
<p>Pak musíme přesunout bootovací soubory do bootovacího oddílu: <code class="language-plaintext highlighter-rouge">mv /mnt/archpi/root/boot/* boot</code> a tím jsme hotovi, stačí oddíly odpojit příkazem <code class="language-plaintext highlighter-rouge">umount /mnt/archpi/root</code> a <code class="language-plaintext highlighter-rouge">umount /mnt/archpi/boot</code>. Jakmile se příkazy dokončí, můžete SD kartu vložit do RPi a zapnout.</p>
<p>Výchozí jméno a zároveň heslo uživatele je <code class="language-plaintext highlighter-rouge">alarm</code> a roota <code class="language-plaintext highlighter-rouge">root</code>. Než bude systém nastavený, doporučuji použít <code class="language-plaintext highlighter-rouge">root</code> účet.</p>
<h1 id="připojení-k-wi-fi-síti">Připojení k Wi-Fi síti</h1>
<p><em>Pokud používáte kabelové připojení, tak můžete přeskočit</em>
Nyní se připojíme skrz terminál k Wi-Fi síti. Předpokládám, že název (SSID) sítě a heslo znáte a že zabezpečení je WPA2 Personal. Jinak si můžete prohlédnout <a href="https://wiki.archlinux.org/title/Network_configuration/Wireless">Arch Wiki</a> pro více návodů.</p>
<p>Příkazem <code class="language-plaintext highlighter-rouge">iw dev</code> zjistíte název vašeho interfacu (např. já mám <code class="language-plaintext highlighter-rouge">wlan0</code>). Zapneme ho pomocí <code class="language-plaintext highlighter-rouge">ip link wlan0 up</code> (místo <code class="language-plaintext highlighter-rouge">wlan0</code> tedy použijte váš název interfacu).</p>
<p>Dále se tedy připojíme k nějaké Wi-Fi síti. Nejdřív musíme vytvořit konfigurační soubor pro <code class="language-plaintext highlighter-rouge">wpa_supplicant</code>, který slouží jako <a href="https://cs.wikipedia.org/wiki/Suplikant">suplikant</a> s podporou WPA, WPA2 a WPA3.</p>
<p>Pomocí příkazu <code class="language-plaintext highlighter-rouge">nano /etc/wpa_supplicant/wpa_supplicant.conf</code> vstoupíme do editace konfiguračního souboru. Do něj vložíme následující dva řádky:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ctrl_interface=/run/wpa_supplicant
update_config=1
</code></pre></div></div>
<p>Klávesovou zkratkou <code class="language-plaintext highlighter-rouge">Ctrl+X</code>, zadáním <code class="language-plaintext highlighter-rouge">y</code> a potvrzením enterem uložíme soubor a opustíme editaci. wpa_supplicant teď můžeme spustit příkazem <code class="language-plaintext highlighter-rouge">wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf</code>.</p>
<p>S běžícím wpa_supplicant můžeme použít příkaz <code class="language-plaintext highlighter-rouge">wpa_cli</code>, kde můžeme konfigurovat síť.</p>
<p>Sítě zde můžete hledat příkazem <a href="https://wiki.archlinux.org/title/Wpa_supplicant#Connecting_with_wpa_cli"><code class="language-plaintext highlighter-rouge">scan</code></a>, následováný <code class="language-plaintext highlighter-rouge">scan_results</code>.</p>
<p>Pro přidání sítě použijeme příkaz <code class="language-plaintext highlighter-rouge">add_network</code>. Terminál vrátí <code class="language-plaintext highlighter-rouge">0</code>, což je ID sítě, které můžeme konfigurovat. Příkazem <code class="language-plaintext highlighter-rouge">set_network 0 ssid "MYSSID"</code> nastavíme SSID (název) sítě na <code class="language-plaintext highlighter-rouge">MYSSID</code>. Příkazem <code class="language-plaintext highlighter-rouge">set_network 0 psk "passphrase"</code> nastavíme heslo na <code class="language-plaintext highlighter-rouge">passphrase</code>. Jakmile je nastaveno, můžeme povolit síť pomocí <code class="language-plaintext highlighter-rouge">enable_network 0</code>. Konfiguraci uložíme příkazem <code class="language-plaintext highlighter-rouge">save_config</code> a opustíme pomocí <code class="language-plaintext highlighter-rouge">quit</code>.</p>
<p>Jelikož ale právě teď nemáme IP adresu, musíme nastavit službu DHCP (pokud ji samozřejmě váš router má). Stačí zapnout službu <code class="language-plaintext highlighter-rouge">dhcpcd</code> pomocí příkazu <code class="language-plaintext highlighter-rouge">systemctl enable dhcpcd</code>. Abychom při každém zapnutí nemuseli síť manuálně zapínat, můžeme do <code class="language-plaintext highlighter-rouge">dhcpcd</code> přidat <a href="https://wiki.archlinux.org/title/Dhcpcd#10-wpa_supplicant">hook</a>, který ji automaticky zapne, stačí použít <code class="language-plaintext highlighter-rouge">ln -s /usr/share/dhcpcd/hooks/10-wpa_supplicant /usr/lib/dhcpcd/dhcpcd-hooks/</code>.</p>
<p>V tomto stádiu doporučuji restartovat příkazem <code class="language-plaintext highlighter-rouge">reboot</code>.</p>
<h1 id="nastavujeme-správce-balíků">Nastavujeme správce balíků</h1>
<p>Aktuálně bychom měli mít funkční síť, nicméně je potřeba pár dalších příkazů pokud chceme používat <code class="language-plaintext highlighter-rouge">pacman</code> správce balíků.</p>
<p>Nejdřív musíme vytvořit klíčenku příkazem <code class="language-plaintext highlighter-rouge">pacman-key --init</code>, poté přidáme klíče Arch ARM repozitářů příkazem <code class="language-plaintext highlighter-rouge">pacman-key --populate archlinuxarm</code>. Teď můžete příkazem <code class="language-plaintext highlighter-rouge">pacman -Sy</code> repozitáře synchronizovat.</p>
<p>Jako první balík bychom měli stáhnout <a href="https://wiki.archlinux.org/title/sudo"><code class="language-plaintext highlighter-rouge">sudo</code></a>, abychom nemuseli používat <code class="language-plaintext highlighter-rouge">root</code> uživatele pro všechno nastavování. Nainstalujeme ho příkazem <code class="language-plaintext highlighter-rouge">pacman -S sudo</code>. Dále příkazem <code class="language-plaintext highlighter-rouge">nano /etc/sudoers</code> upravíme konfiguraci. Najdeme následující řádky (<code class="language-plaintext highlighter-rouge">Ctrl+W</code> pro hledání):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>## Uncomment to allow members of group wheel to execute any command
#%wheel ALL=(ALL:ALL) ALL
</code></pre></div></div>
<p>a odstraníme mřížku před <code class="language-plaintext highlighter-rouge">%</code> pro odstranění komentáře. Tím umožníme uživatelům v uživatelské skupině <code class="language-plaintext highlighter-rouge">wheel</code> používat příkaz <code class="language-plaintext highlighter-rouge">sudo</code>.</p>
<p>Nyní přidáme uživatele <code class="language-plaintext highlighter-rouge">alarm</code> do skupiny <code class="language-plaintext highlighter-rouge">wheel</code> příkazem <code class="language-plaintext highlighter-rouge">gpasswd -a alarm wheel</code>. A teď už můžeme používat uživatele <code class="language-plaintext highlighter-rouge">alarm</code> pro různé administrativní operace místo roota.</p>
<h1 id="nastavení-ssh-přístupu">Nastavení SSH přístupu</h1>
<p>Možná vás nebaví zapojovat RPi do monitoru nebo u něj klapat věci do klávesnice v terminálu nebo jen chcete vzdálený přístup. SSH lze povolit skrz OpenSSH, které je na Archu předinstalované. Stačí povolit službu pomocí <code class="language-plaintext highlighter-rouge">systemctl enable sshd</code>. Pro nějakou pokročilou konfiguraci si prohlédněte <a href="https://wiki.archlinux.org/title/OpenSSH#Server_usage">Arch Wiki</a>.</p>
<p>Nyní se stačí připojit skrz nějaký SSH klient na vaše zařízení (pokud neznáte IP, podívejte se skrz příkaz <code class="language-plaintext highlighter-rouge">ip a</code>), třeba skrz <code class="language-plaintext highlighter-rouge">ssh alarm@vase.ip.adresa</code>.</p>
<h1 id="https-problémy">HTTPS problémy</h1>
<p>Pokud máte problémy s SSL nebo komunikací se zabezpečenými servery, zkuste nainstalovat balík <code class="language-plaintext highlighter-rouge">ca-certificates</code> a nastavit systémový čas skrz <code class="language-plaintext highlighter-rouge">timedatectl set-time "2022-10-29 15:00:00</code> (samozřejmě vaše datum).</p>
<h1 id="závěr">Závěr</h1>
<p><img src="/assets/images/rpi-arch/05.png" alt="Arch neofetch" /></p>
<p>Instalace je opravdu prostý a snadný proces (i když jsem ho sám dělal asi 5x než mi to nabootovalo), takže určitě zkoušejte a zkoušejte.</p>]]></content><author><name>hernikplays</name></author><category term="tutoriál" /><category term="návod" /><category term="rpi" /><category term="arch" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">NordVPN - Jste opravdu v takovém nebezpečí?</title><link href="https://caras.cafe/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn.html" rel="alternate" type="text/html" title="NordVPN - Jste opravdu v takovém nebezpečí?" /><published>2022-07-19T00:00:00+00:00</published><updated>2022-07-19T00:00:00+00:00</updated><id>https://caras.cafe/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn</id><content type="html" xml:base="https://caras.cafe/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn.html"><![CDATA[<p>Pokud sledujete YouTube, určite jste už narazili na nespočet videí, které sponzoruje nějaký poskytovatel tzv. <strong>VPN</strong>. Většinou se dozvíte něco jako „vaše data jsou v nebezpečí“ a/nebo „použijte naše služby pro zabezpečení vašich dat před hackery“. Toto se samozřejmě netýká <em>jen</em> NordVPN, ale myslím, že ti mají tu nejagresivnější marketingovou strategii snad ze všech.</p>
<h1 id="část-i-kecy">ČÁST I: Kecy</h1>
<h2 id="kdo-stojí-za-nordvpn">Kdo stojí za NordVPN</h2>
<p>NordVPN vzniklo v roce 2012 jako produkt Toma Okmana, Eimantase Sabaliauskase a Jonase Karklyse. Služba má sloužit jako tzv. <strong>Virtual Private Network</strong> neboli virtuální soukromá síť. Můžete se tak skrze NordVPN servery připojovat na internet třeba z Německa. Dle zvoleného protokolu je síťový provoz šifrován. NordVPN vlastní společnost <a href="https://nordsecurity.com/">Nord Security</a>, která zastřešuje i ostatní produkty značky Nord. Sídlo má ve Velké Británii. Nord Security kromě VPN nabízí i vlastního správce hesel a šifrovaný cloud.</p>
<h2 id="nordvpn-a-reklamy-youtuberů">NordVPN a reklamy YouTuberů</h2>
<p>Reklamy uvnitř obsahu, tedy reklamy, které tvůrce přidává přímo do videa výměnou za přímou platbu od společnosti, jsou tu s námi celkem dlouho. Jsou <strong>efektivnější</strong> než běžné reklamy, protože je s běžným blokovačem reklam nepřeskočíte a často je tvůrci tvoří zábavným způsobem, aby je sledující sám nepřeskočil. Je to <strong>stabilnější příjem</strong> pro tvůrce obsahu, jelikož se nemusí spoléhat na výdělek z reklam, které YouTube často omezuje svými pravidli demonetizace. To je také jeden z důvodů, proč často youtubeři těmto druhům reklam vyjdou vstříc, i když nemusí mít o daném produktu žádnou znalost. Často tak ve svých videích poskytují nepravdivé či přímo zavádějící tvrzení. Než uvedu příklady, je nutné si uvědomit, že <strong>ne každý takový YouTuber poskytuje zavádějící informace</strong> nebo že <strong>NordVPN nejsou žádní podvodníci</strong>. Nejsem žádný „samozvaný IT expert“, takže mě neváhejte případně opravit. A o tvrzení „NordVPN je nejlepší VPN“ se bavit ani nebudu, o tom si udělejte obrázek sami.</p>
<h3 id="tvrzení-č-1">Tvrzení č. 1:</h3>
<p><strong><a href="https://youtu.be/51TNTCAD8fQ?t=68">Veřejné WiFi jsou nebezpečné a kdokoliv může sledovat, co na nich děláte</a></strong></p>
<p>Zalíbila se mi <a href="https://www.quora.com/Is-it-safe-to-use-internet-from-open-public-WiFi-hotspots/answer/Scott-Helms-8">odpověď Scotta Helmse</a>, který přirovnává veřejné WiFi sítě k veřejným ulicím. Pokud budete dělat hlouposti, jako je chození s přilepenou platební kartou na čele, samozřejmě vaše údaje budou odcizeny. Proto určitě není dobrý nápad dělat nákupy či se přihlašovat do bankovnictví skrz veřejné sítě. Když se na to podíváme realisticky, je relativně malá šance, že si zrovna k vám v mekáči sedl chlapec či dívka s laptopem, na kterém projíždí vaši historii vyhledávání. Navíc většina webů je zabezpečená pomocí SSL, takže přenos dat je šifrovaný. Takže při používání VPN to vlastně šifrujete ještě jednou (?), což už ale tak užitečné není. Jak <a href="https://www.eff.org/deeplinks/2020/01/why-public-wi-fi-lot-safer-you-think">píše</a> EFF, tyto hrozby jsou díky HTTPS/SSL spíše minulostí. Váš poskytovatel internetu může sledovat např. jakou stránku otevíráte (třeba github.com), nicméně neuvidí žádné parametry, které odesíláte, ani jestli navštěvujete github.com/hernikplays nebo github.com/ytdl. A to stejné mohou lidé, kteří jsou kolem vás připojení na veřejné WiFi. „V životě se bojíte spousty věcí, veřejné WiFi si můžete ze seznamu odškrtnout“.</p>
<h3 id="tvrzení-č-2">Tvrzení č. 2:</h3>
<p><strong><a href="https://youtu.be/a_LiGXtXXNQ?t=1642">[NordVPN poskytuje] maximální internetové bezpečí</a></strong></p>
<p>Jak už jsem řekl v předchozí části, před vlastní blbostí vás ani to nejlepší VPN nezachrání. Pokud máte selský rozum, tak poznáte, kam zadávat a nezadávat svoje osobní údaje, což se s rostoucí popularitou sociálního inženýrství o něco zhoršuje. A pokud si vás přecijen nějaký špičkový, státem placený hacker najde, tak mu VPN určitě nebude dělat problém.</p>
<h3 id="tvrzení-č-3">Tvrzení č. 3:</h3>
<p><strong><a href="https://youtu.be/sB8vHDS1Tcg?t=380">Zatímco [bez VPN] ti může jakýkoliv útočník vcelku jednoduše tvé zařízení nabourat, s ním jsi prakticky neviditelný […] smaže za tebou tvou stopu</a></strong></p>
<p>Toto tvrzení je možná pravdivé pro NordVPN, jelikož nabízejí službu „<a href="https://nordvpn.com/features/threat-protection/">Threat Protection</a>“, která slouží k blokování reklam, sledovacích prvků a nebezpečných webů, nicméně může vzbudit dojem, že takhle operuje každé VPN. Pokud vám jde o vaše bezpečí, neměli byste sázet na řešení jedním kliknutím, ale <a href="https://mullvad.net/en/help/first-steps-towards-online-privacy/">prozkoumat různé možnosti a nástroje</a>, včetně VPN. Pokud používáte např. služby od Googlu, už tak jim o sobě poskytujete dostatek údajů.
Útočník také nemůže „vcelku jednoduše“ vaše zařízení nabourat, to lze pouze pokud jste se rozhodli používat Windows 10 a nenainstalovali jste žádné aktualizace. V tom případě je váš systém děravý jak ementál a to už asi nikdo, kromě vás, nespraví. Takže aktualizujte svůj systém a aplikace jak to jen půjde!</p>
<h3 id="tvrzení-č-4">Tvrzení č. 4:</h3>
<p><strong>Můžeš sledovat obsah uzamknutý pro určité země</strong></p>
<p>To je samozřejmě pravda, nicméně některé služby se aktivně pokouší zamezit přístup uživatelům s VPN identifikováním IP adresy daného VPN serveru.</p>
<h3 id="tvrzení-č-5">Tvrzení č. 5:</h3>
<p><strong><a href="https://youtu.be/sB8vHDS1Tcg?t=436">[NordVPN] ti zrychlí internet</a></strong></p>
<p>Když máte od poskytovatele internetu omezené stahování na 10 MB/s, nemůžete očekávat, že když budete ze serveru, kde může být zároveň napojeno X tisíc lidí a je někde v tramtárii, stahovat soubor, že se bude stahovat rychleji. <a href="https://www.cloudflare.com/learning/access-management/vpn-speed/">Pouze ve specifických případech</a>, kdy například poskytovatel internetu záměrně zpomaluje připojení např. k Netflixu, můžete pocítit zrychlení.</p>
<h2 id="nordvpn-a-ještě-divnější-praktiky">NordVPN a ještě divnější praktiky</h2>
<p>Zavádějícími tvrzeními to však nekončí, věděli jste, že na mnoha webech s hodnoceními VPN služeb si můžete určitou pozici <strong>jednoduše koupit</strong>? Ano, dostáváme se do takzvaného <strong>provizního systému</strong>, tedy systému, ve kterém firma proplatí provizi z provedeného nákupu jistému zprostředkovateli. Vtipná věc je, že některé tyto firmy <a href="https://blog.windscribe.com/consolidation-of-the-vpn-industry-spells-trouble-for-the-consumer-57e638634cf0/">vlastní</a> zároveň takovéto <em>„publikace“</em> a samotné VPN služby, jako např. Kape Technologies, která se původně <strong>zabývala adwarem</strong>, nyní vlastní např. ExpressVPN a zároveň web VPNmentor. NordVPN není výjimkou s jejich provizním systémem nabízejícím až 40% část z ceny nákupu. Dá se těmto „hodnocením“ vůbec věřit? Některým nejspíš ano, je dobré však zkontrolovat, jestli publikaci nevlastní nějaká mediální společnost.</p>
<p>Dále můžeme na webu NordVPN, služby, která vám má pomoct chránit vaše soukromí a <em>„zneviditelnit se“</em>, <strong>najít spoustu sledovacích prvků</strong>, jako např. sledovací prvky Twitter Ads, Google Ads, Analytics a Bing.</p>
<p><img src="/assets/images/vpn/14.png" alt="Ukázka sledovacích prvků na stránce NordVPN" /></p>
<h1 id="část-ii-vzhůru-dolů">Část II: Vzhůru dolů</h1>
<p>Ano, je čas, abych se vydal do králičí nory a NordVPN otestoval. Hned na úvodní stránce na vás vyskočí tuny slev. „Nakupte do X hodin a získejte slevu X%“. No tak to abych si pohnul, co? Samozřejmě, že ne. Úplně stejná stránka s úplně stejným odpočtem se mi zobrazila i včera. Navíc tato sleva platí jen na roční plány a já s NordVPN chci strávit co nejméně času. Takže beru jejich standardních 10,49 eur na měsíc, které naštěstí také nabízejí s garancí vrácení peněz. Samozřejmě k tomu ještě musíte přičíst daně, z čehož máme 12,69 <em>(nice)</em>. Použil jsem jejich <a href="https://www.theregister.com/2020/03/06/nordvpn_no_auth_needed_view_user_payments/">(ne)</a>bezpečnou bránu a vzdal se svých těžce vydělaných peněz.
Jejich stránka, ze které jsem měl stáhnout klienta, se chvástala „online zabezpečením pro všechny velké linuxové distribuce“, takže je super, že nabízejí stažení pouze pro distribuce založené na Debianu a RHEL, když jsem na Archu. Samozřejmě nic, co by Arch komunita nevyřešila.</p>
<p>Nemůžu hodnotit jednoduchost prostředí, protože <em>to na linuxu ani není</em>. Nicméně se podíváme na rychlost.</p>
<h2 id="rychlosti-velmi-stručně">Rychlosti (velmi stručně)</h2>
<p><img src="/assets/images/vpn/13.png" alt="Výchozí rychlost (bez VPN, WiFi)" /></p>
<p>Výchozí rychlost (bez VPN, WiFi)</p>
<p><img src="/assets/images/vpn/12.png" alt="NordVPN Germany #1078" /></p>
<p>NordVPN Germany #1078</p>
<p><img src="/assets/images/vpn/11.png" alt="Rychlost stahování torrentů na serverech v Německu" /></p>
<p>Pokles rychlosti, úplně normální, protože pakety urazí větší vzdálenost. Streamování YouTube ve Full HD má pocititelné zpomalení/zasekávání. Rychlosti stahování torrentů se držely v průměru mezi 600 a 700 KB/s.</p>
<p><img src="/assets/images/vpn/10.png" alt="NordVPN USA #9363" /></p>
<p>NordVPN USA #9363</p>
<p><img src="/assets/images/vpn/9.png" alt="Rychlost stahování torrentů na serverech v USA" /></p>
<p>Tady už změnu pocítíte víc. Zajímavé však je, že se videa z YouTube ve Full HD načítají rychleji. Nicméně rychlosti stahování torrentů skákaly nahorů a dolů.</p>
<h2 id="threat-protection-lite">Threat Protection Lite</h2>
<p>Další funkce dostupná pro linux je <a href="https://support.nordvpn.com/General-info/Features/1047407402/What-are-Threat-Protection-and-Threat-Protection-Lite.htm">TPL</a>, který má blokovat reklamy, nebezpečné stránky a pochybná připojení během připojení na VPN.</p>
<p>Na webu NordVPN zablokoval sledovací prvky Twitteru, Bingu a Googlu, nicméně vynechal Google Analytics (což je asi pochopitelné, když o blokování sledujících prvků není ani zmínka).</p>
<p><img src="/assets/images/vpn/8.png" alt="Zablokované sledovací prvky na NordVPN.com" /></p>
<p>Na YouTube neblokuje reklamy vůbec,
<img src="/assets/images/vpn/7.png" alt="Blokování reklam s TPL na YouTube" /></p>
<p>ale na jiných webech ano.
<img src="/assets/images/vpn/6.png" alt="Blokování reklam s TPL na jiných webech" /></p>
<p>Takže nahradí blokovače jako <a href="https://github.com/gorhill/uBlock#readme">uBlock Origin</a>? Řekl bych, že ne.</p>
<h1 id="část-iii-opouštíme-králičí-noru">Část III: Opouštíme králičí noru</h1>
<p>Dobře, mám trochu NordVPN na vlastní kůži, ale teď se ho chci zbavit. Takže jdeme žádat zpět peníze.
Zrušení obnovení předplatného bylo relativně snadné, v nastavení účtu stačilo kliknout na „Zrušit“.</p>
<p><img src="/assets/images/vpn/5.png" alt="Zrušení obnovení předplatného" /></p>
<p>Teď přijde ta bolestivější část, a to žádání o vrácení peněz. Dle podmínek máte 30 dní od prvního nákupu nárok na vrácení peněz.
NordVPN říká, že podpora funguje 24/7. Na začátku jste spojeni s robotem, který vás postupně přepojí na živého člověka.</p>
<p><img src="/assets/images/vpn/4.png" alt="Robot na podpoře" /></p>
<p>Člověk se skutečně objevil.</p>
<p><img src="/assets/images/vpn/3.png" alt="Chat s podporu část 1" /></p>
<p>Chvilku mu to trvalo, takže jsem ho popostrčil.</p>
<p><img src="/assets/images/vpn/2.png" alt="Chat s podporu část 2" /></p>
<p>Řekl jsem mu slušně „Ne, díky“, po čemž mi nastavil vrácení peněz.</p>
<p><img src="/assets/images/vpn/1.png" alt="Chat s podporu část 3" /></p>
<p>Celkem rychle vyřízeno, dobrá práce. Zvláštní mi přišlo jen, že si mě nijak neověřil, pouze jsem na začátku poskytl e-mail, z čehož (doufám) vydedukoval, že to patří k mému účtu.
Další den mi skutečně odebrali přístup k jejich službě, nicméně peníze jsou stále zablokované, tak snad si banka pohne.</p>
<h1 id="část-v-závěr">Část V: Závěr</h1>
<p>Takže na závěr:
<strong>Je VPN úplně zbytečný nástroj?</strong> Určitě ne.</p>
<p><strong>Můžou youtubeři za to, že někdy neříkají pravdivé věci?</strong> Spíš ne, nemůžete čekat každého youtubera, že je expert přes sítě, jenom se snaží se uživit a vyloženě lži říkají opravdu málokdy.</p>
<p><strong>Snaží se NordVPN prodat hadí olej a moje děti na darknetu?</strong> Nejspíš ne, ale měli by víc sjednotit prezentování co se týče sponzorování youtuberů.</p>
<p><strong>Můžu důvěřovat NordVPN?</strong> S jejich velikostí nejspíš ano.</p>
<p><strong>Doporučil bych NordVPN?</strong> Ne. Pokud chcete opravdu 100% anonymitu a hlavně no-bullshit produkt, použijte něco jako Mullvad <em>(toto není sponzorováno, sám ho používám a je fajn)</em>, který nenabízí žádné posrané slevy kvůli všemu možnému a kde dokonce můžete platit v hotovosti, ale nezapomeňte, že VPNkem to nekončí. Podívejte se na <a href="https://ssd.eff.org/">Surveillance Self-Defense</a> od EFF pro více tipů na ochranu vašeho soukromí.</p>]]></content><author><name>hernikplays</name></author><category term="bezpečí" /><category term="vpn" /><category term="youtube" /><category term="reklamy" /><summary type="html"><![CDATA[Pokud sledujete YouTube, určite jste už narazili na nespočet videí, které sponzoruje nějaký poskytovatel tzv. VPN. Většinou se dozvíte něco jako „vaše data jsou v nebezpečí“ a/nebo „použijte naše služby pro zabezpečení vašich dat před hackery“. Toto se samozřejmě netýká jen NordVPN, ale myslím, že ti mají tu nejagresivnější marketingovou strategii snad ze všech. ČÁST I: Kecy Kdo stojí za NordVPN NordVPN vzniklo v roce 2012 jako produkt Toma Okmana, Eimantase Sabaliauskase a Jonase Karklyse. Služba má sloužit jako tzv. Virtual Private Network neboli virtuální soukromá síť. Můžete se tak skrze NordVPN servery připojovat na internet třeba z Německa. Dle zvoleného protokolu je síťový provoz šifrován. NordVPN vlastní společnost Nord Security, která zastřešuje i ostatní produkty značky Nord. Sídlo má ve Velké Británii. Nord Security kromě VPN nabízí i vlastního správce hesel a šifrovaný cloud.]]></summary></entry><entry><title type="html">GitHub Codespaces aneb VS Code na VPS</title><link href="https://caras.cafe/vychyt%C3%A1vky/2022/05/31/codespaces.html" rel="alternate" type="text/html" title="GitHub Codespaces aneb VS Code na VPS" /><published>2022-05-31T00:00:00+00:00</published><updated>2022-05-31T00:00:00+00:00</updated><id>https://caras.cafe/vychyt%C3%A1vky/2022/05/31/codespaces</id><content type="html" xml:base="https://caras.cafe/vychyt%C3%A1vky/2022/05/31/codespaces.html"><![CDATA[<p>Nedávno mi přišel e-mail, že jsem byl přidán do beta testování funkce Codespaces na GitHubu. Stručně, Codespaces má být systém ve kterém si vytvoříte vlastní prostředí pro váš repozitář, do kterého si nainstalujete všechny potřebné knihovny, SDK a balíky. Server, na kterém to všechno běží, si platíte u GitHubu a můžete na něj kdekoliv a kdykoliv přejít přes web do webové, narozdíl od výchozího webového VS Code plně vybavené, verzi VS Code nebo nainstalovaný VS Code a upravovat nebo testovat kód.</p>
<p>Hodí se pro lidi, kteří nechtějí tahat např. do školy nebo do práce, kde nesmí instalovat externí aplikace, svůj vlastní notebook.
Parametry</p>
<p>V betě je možné testovat pouze výchozí možnost 4 jádra + 8GB RAM + 32GB úložiště, což definitivně stačí pro osobní a malé projekty. Do konce bety neplatíte nic, ale 4 jádra vyjdou na $0.36 (asi 8,3 kč) za hodinu, tj za hodinu aktivního používání. Codespace se vám automaticky vypne, pokud není po stanovenou dobu nepoužíván, takže můžete předejít placení katastrofických částek.
<img src="/assets/images/codespaces/1.jpg" alt="Ceny Codespaces" /></p>
<p>Je to určitě výhodnější, než si platit např. hotové VPS, pokud ho tedy nepoužíváte i na něco smysluplnějšího.
Moje zkušenost</p>
<p>Samozřejmě jsem nemohl odolat a na OpenCanteen jsem si jeden nechal vytvořit, aniž bych věděl do čeho se vrhám.</p>
<p>Codespace se vytváří jednoduše kliknutím na tlačítko “Code” ve vašem repozitáří, kde se vám nově zobrazí možnost si Codespace vytvořit.</p>
<p>Ve výchozím stavu běží server na Ubuntu. Pokud nenajdete docker obraz nebo devcontainer konfigurační soubor, musíte si samozřejmě vše nainstalovat sami, což zas tolik nevadí, protože to nejspíš budete dělat jen jednou, pokud si nebudete s obrazem stroje nějak zahrávat.</p>
<p>Instalace všeho však probíhá svižně, jelikož asi v Microsoftu mají na rychlejší internet, než já. Samozřejmě vše musíte instalovat skrze terminál (což mě celkem ranilo, jelikož instalovat Android SDK pro flutter byla celkem fuška).</p>
<p>Pokud používáte Settings Sync ve VS Code, automaticky se vám synchronizují nastavení a rozšíření. Pro pokročilé upravení prostředí slouží konfigurační soubor devcontainer.json
<img src="/assets/images/codespaces/2.jpg" alt="Ceny Codespaces" /></p>
<p>Jakmile máte všechno nastavené, už stačí jen využít starého známého Visual Studio Code, které funguje úplně stejně jako na lokálním zařízení. Na Codespace se můžete kdykoli připojit přes webovou adresu.</p>
<p>Za mě velice praktické pro dříve uvedené typy lidí, už jen záleží, jestli se to zrovna vám za ty peníze vyplatí. Dokumentace je možná trochu chaotická, alespoň pro uživatele co se nevyznají v technologiích jako kontejnery či docker a většiny funkcí využije jen skutečný poweruser (což já určitě nejsem).</p>]]></content><author><name>hernikplays</name></author><category term="vychytávky" /><category term="github" /><category term="vps" /><summary type="html"><![CDATA[Nedávno mi přišel e-mail, že jsem byl přidán do beta testování funkce Codespaces na GitHubu. Stručně, Codespaces má být systém ve kterém si vytvoříte vlastní prostředí pro váš repozitář, do kterého si nainstalujete všechny potřebné knihovny, SDK a balíky. Server, na kterém to všechno běží, si platíte u GitHubu a můžete na něj kdekoliv a kdykoliv přejít přes web do webové, narozdíl od výchozího webového VS Code plně vybavené, verzi VS Code nebo nainstalovaný VS Code a upravovat nebo testovat kód.]]></summary></entry><entry><title type="html">Automatizace, automatizace, automatizace</title><link href="https://caras.cafe/programov%C3%A1n%C3%AD/2022/05/22/automatizace.html" rel="alternate" type="text/html" title="Automatizace, automatizace, automatizace" /><published>2022-05-22T00:00:00+00:00</published><updated>2022-05-22T00:00:00+00:00</updated><id>https://caras.cafe/programov%C3%A1n%C3%AD/2022/05/22/automatizace</id><content type="html" xml:base="https://caras.cafe/programov%C3%A1n%C3%AD/2022/05/22/automatizace.html"><![CDATA[<p>Roboti nám brzo vezmou práci, ale mně to (prozatím) nevadí. Já nechávám robůtky pracovat za mě a ulehčovat mi práci. A vy byste měli taky! Pokud teda programujete, jinak nevím.</p>
<p>Nedávno jsem objevil krásy zvané GitHub Actions a musím říct, že je to opravdu radost. Nikdy předtím jsem nedokázal pochopit jejich praktičnost, než jsem pracoval na <a href="https://github.com/hernikplays/opencanteen">OpenCanteen</a>. Sestavovat, podepisovat a nahrávat mě opravdu nebavilo a ještě s mým pomalým PC v kombinaci s pomalým internetem to nešlo zrovna rychle. Pak jsem si vzpomněl na GitHub Actions. Místo toho, abych dělal cokoliv produktivního, jsem strávil celé odpoledne nastavováním Actions, aby mi při novém tagu automaticky sestavil a publikoval vydání aplikace do Google Play.</p>
<p>Ta první část šla skvěle, avšak nahrávání do Google Play bylo o něco složitější, dokud jsem neobjevil hotové a, prozatím bezplatné, řešení <a href="https://codemagic.io/start/">CodeMagic</a>.</p>
<p>Jednoduše jsem napojil repozitář, nastavil podepisovací a nahrávací údaje a všechno hned jelo! Byla to radost pro někoho tak líného jako jsem já. I přesto, že jsem sám reálně nic neudělal, cítil jsem, že jsem dosáhl něčeho úžasného.</p>
<p>A určitě to lze dotáhnout ještě dál, už teď používám Actions pro automatickou analýzu kódu, a kdybych si vytvořil testy tak by mi to určitě i otestovalo celou aplikaci.</p>
<p>Pak jsem si řekl, že by možná mohl někdo chtít do mé aplikace přispět svým kódem. Protože chci v tom mít pořádek, hned jsem začal projíždět GitHub Marketplace pro nějaké akce na pull requesty. Hned jsem jich několik objevil.</p>
<p>Velice jsem ocenil akci, která mi automaticky přidala labely podle souboru, který byl v PR upraven.</p>
<p>Určitě nepotřebujete nutně automatizovat všechno, pokud máte např. soukromý či malý projekt. Nicméně si to můžete aspoň otestovat a případně využít v budoucnu tak se do toho pusťte! Automatizovat můžete všechno možné. Určitě budete mít dobrý pocit, když se vaše akce spustí a úspěšně se dokončí.</p>]]></content><author><name>hernikplays</name></author><category term="programování" /><category term="automatizace" /><category term="technologie" /><summary type="html"><![CDATA[Roboti nám brzo vezmou práci, ale mně to (prozatím) nevadí. Já nechávám robůtky pracovat za mě a ulehčovat mi práci. A vy byste měli taky! Pokud teda programujete, jinak nevím.]]></summary></entry></feed>

1073
index.html

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,750 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="google-translate-customization" content="108d9124921d80c3-80e20d618ff053c8-g4f02ec6f3dba68b7-c">
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>Automatizace, automatizace, automatizace | Matyáš Caras</title>
<meta name="generator" content="Jekyll v4.3.1">
<meta property="og:title" content="Automatizace, automatizace, automatizace">
<meta name="author" content="hernikplays">
<meta property="og:locale" content="en_US">
<meta name="description" content="Roboti nám brzo vezmou práci, ale mně to (prozatím) nevadí. Já nechávám robůtky pracovat za mě a ulehčovat mi práci. A vy byste měli taky! Pokud teda programujete, jinak nevím.">
<meta property="og:description" content="Roboti nám brzo vezmou práci, ale mně to (prozatím) nevadí. Já nechávám robůtky pracovat za mě a ulehčovat mi práci. A vy byste měli taky! Pokud teda programujete, jinak nevím.">
<link rel="canonical" href="https://caras.cafe/programov%C3%A1n%C3%AD/2022/05/22/automatizace.html">
<meta property="og:url" content="https://caras.cafe/programov%C3%A1n%C3%AD/2022/05/22/automatizace.html">
<meta property="og:site_name" content="Matyáš Caras">
<meta property="og:type" content="article">
<meta property="article:published_time" content="2022-05-22T00:00:00+00:00">
<meta name="twitter:card" content="summary">
<meta property="twitter:title" content="Automatizace, automatizace, automatizace">
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"BlogPosting","author":{"@type":"Person","name":"hernikplays"},"dateModified":"2022-05-22T00:00:00+00:00","datePublished":"2022-05-22T00:00:00+00:00","description":"Roboti nám brzo vezmou práci, ale mně to (prozatím) nevadí. Já nechávám robůtky pracovat za mě a ulehčovat mi práci. A vy byste měli taky! Pokud teda programujete, jinak nevím.","headline":"Automatizace, automatizace, automatizace","mainEntityOfPage":{"@type":"WebPage","@id":"https://caras.cafe/programov%C3%A1n%C3%AD/2022/05/22/automatizace.html"},"url":"https://caras.cafe/programov%C3%A1n%C3%AD/2022/05/22/automatizace.html"}</script>
<!-- End Jekyll SEO tag -->
<link rel="shortcut icon" href="">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/typeface-noto-sans@0.0.72/index.min.css">
<link rel="stylesheet" href="/assets/css/main.css">
<script src="/assets/js/main.js"></script><link type="application/atom+xml" rel="alternate" href="https://caras.cafe/feed.xml" title="Matyáš Caras">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js"></script>
<!-- and it's easy to individually load additional languages -->
<script charset="UTF-8" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/languages/go.min.js"></script>
<script>
// Init highlight js
document.addEventListener('DOMContentLoaded', function(event) {
var els = document.querySelectorAll('pre code')
function addLangData(block) {
var outer = block.parentElement.parentElement.parentElement;
var lang = block.getAttribute('data-lang');
for (var i = 0; i < outer.classList.length; i++) {
var cls = outer.classList[i];
if (cls.startsWith('language-')) {
lang = cls;
break;
}
}
if (!lang) {
cls = block.getAttribute('class');
lang = cls ? cls.replace('hljs ', '') : '';
}
if (lang.startsWith('language-')) {
lang = lang.substr(9);
}
block.setAttribute('class', 'hljs ' + lang);
block.parentNode.setAttribute('data-lang', lang);
}
function addBadge(block) {
var enabled = ('true' || 'true').toLowerCase();
if (enabled == 'true') {
var pre = block.parentElement;
pre.classList.add('badge');
}
}
function handle(block) {
addLangData(block);
addBadge(block)
hljs.highlightBlock(block);
}
for (var i = 0; i < els.length; i++) {
var el = els[i];
handle(el);
}
});
</script>
<style>
/* code language badge */
pre.badge::before {
content: attr(data-lang);
color: #fff;
background-color: #ff4e00;
padding: 0 .5em;
border-radius: 0 2px;
text-transform: uppercase;
text-align: center;
min-width: 32px;
display: inline-block;
position: absolute;
right: 0;
}
/* fix wrong badge display for firefox browser */
code > table pre::before {
display: none;
}
</style>
</head>
<body>
<header class="site-header " role="banner">
<div class="wrapper">
<div class="site-header-inner">
<span class="site-brand"><a class="site-brand-inner" rel="author" href="/">
<img class="site-favicon" title="Matyáš Caras" src="" onerror="this.style.display='none'">
Matyáš Caras
</a>
</span><nav class="site-nav">
<input type="checkbox" id="nav-trigger" class="nav-trigger">
<label for="nav-trigger">
<span class="menu-icon">
<svg viewbox="0 0 18 15" width="18px" height="15px">
<path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"></path>
</svg>
</span>
</label>
<div class="trigger">
<a class="page-link" href="/about.html">ABOUT</a><a class="page-link" href="/archives.html">ARCHIVES</a><a class="page-link" href="/categories.html">CATEGORIES</a><a class="page-link" href="/">HOME</a><a class="page-link" href="/tags.html">TAGS</a>
</div>
</nav>
</div>
</div>
</header>
<script>
function initHeader() {
var lastScrollY = getScrollPos().y;
var documentElement = document.documentElement;
function storeScrollData() {
var y = getScrollPos().y;var scrollStatus = "";
if (y <= 0) {
scrollStatus = "top";
} else if ((window.innerHeight + y) >= document.body.offsetHeight) {
scrollStatus = "bottom";
} else {
var isScrollDown = (y - lastScrollY > 0) ? true : false;
scrollStatus = isScrollDown ? "down" : "up";
}
lastScrollY = y;
documentElement.setAttribute("data-scroll-status", scrollStatus);
}
window.addEventListener('scroll', function(e) {
storeScrollData();
});
storeScrollData();
}
document.addEventListener('DOMContentLoaded', initHeader);
</script>
<script>
function hashLocate(hashValue) {
hashValue = hashValue.replace(/^.*#h-/, '');
hashValue = decodeURIComponent(hashValue);
var element = document.getElementById(hashValue);
if (!element) {
return;
}
var header = document.querySelector('header.site-header');
var headerRect = header.getBoundingClientRect();
var headerTop = Math.floor(headerRect.top);
var headerHeight = Math.floor(headerRect.height);
var scrollPos = getScrollPos();
var offsetY = element.offsetTop - (headerTop + headerHeight + 20);
if (offsetY == scrollPos.y) {
return;
}
if (headerTop == 0 && offsetY > scrollPos.y) {
offsetY += headerHeight + 2;
} else if (headerTop < 0 && offsetY < scrollPos.y) {
offsetY -= headerHeight - 2;
}
smoothScrollTo(offsetY);
}
// The first event occurred
window.addEventListener('load', function(event) {
if (window.location.hash) {
hashLocate(window.location.hash);
}
});
// The first event occurred
window.addEventListener('click', function(event) {
if (event.target.tagName.toLowerCase() == 'a') {
hashLocate(event.target.getAttribute('href'));
}
});
</script>
<div class="theme-toggle">
<input type="checkbox" id="theme-switch">
<label for="theme-switch">
<div class="toggle"></div>
<div class="names">
<p class="light">Light</p>
<p class="dark">Dark</p>
</div>
</label>
</div>
<script>
(function() {
var sw = document.getElementById('theme-switch');
var html = document.getElementsByTagName('html')[0];
var nightModeOption = ('auto' || 'auto').toLowerCase();
var storage = nightModeOption === 'manual'
? localStorage
: sessionStorage;
var themeData = loadThemeData();
function saveThemeData(data) {
storage.setItem('theme', JSON.stringify(data));
}
function loadThemeData() {
var data = storage.getItem('theme');
try {
data = JSON.parse(data ? data : '');
} catch(e) {
data = { nightShift: undefined, autoToggleAt: 0 };
saveThemeData(data);
}
return data;
}
function handleThemeToggle(nightShift) {
themeData.nightShift = nightShift;
saveThemeData(themeData);
html.dataset.theme = nightShift ? 'dark' : 'light';
setTimeout(function() {
sw.checked = nightShift ? true : false;
}, 50);
}
function autoThemeToggle() {
// Next time point of theme toggle
var now = new Date();
var toggleAt = new Date();
var hours = now.getHours();
var nightShift = hours >= 19 || hours <=7;
if (nightShift) {
if (hours > 7) {
toggleAt.setDate(toggleAt.getDate() + 1);
}
toggleAt.setHours(7);
} else {
toggleAt.setHours(19);
}
toggleAt.setMinutes(0);
toggleAt.setSeconds(0);
toggleAt.setMilliseconds(0)
var delay = toggleAt.getTime() - now.getTime();
// auto toggle theme mode
setTimeout(function() {
handleThemeToggle(!nightShift);
}, delay);
return {
nightShift: nightShift,
toggleAt: toggleAt.getTime()
};
}
// Listen the theme toggle event
sw.addEventListener('change', function(event) {
handleThemeToggle(event.target.checked);
});
if (nightModeOption == 'auto') {
var data = autoThemeToggle();
// Toggle theme by local setting
if (data.toggleAt > themeData.autoToggleAt) {
themeData.autoToggleAt = data.toggleAt;
handleThemeToggle(data.nightShift);
} else {
handleThemeToggle(themeData.nightShift);
}
} else if (nightModeOption == 'manual') {
handleThemeToggle(themeData.nightShift);
} else {
var nightShift = themeData.nightShift;
if (nightShift === undefined) {
nightShift = nightModeOption === 'on';
}
handleThemeToggle(nightShift);
}
})();
</script>
<div id="click-to-top" class="click-to-top">
<i class="fa fa-arrow-up"></i>
</div>
<script>
(function () {
const clickToTop = document.getElementById('click-to-top');
window.addEventListener('scroll', () => {
if (window.scrollY > 100) {
clickToTop.classList.add('show')
}else {
clickToTop.classList.remove('show')
}
});
clickToTop.addEventListener('click', () => {
window.smoothScrollTo(0);
});
})();
</script>
<main class="page-content" aria-label="Content">
<div class="wrapper">
<div class="framework">
<section class="main">
<div class="post">
<section>
<header class="post-header">
<h1 class="post-title p-name" itemprop="name headline">Automatizace, automatizace, automatizace</h1>
<h2 class="post-subtitle">Ulehčujeme si život</h2>
<p class="post-meta">
<time class="dt-published" datetime="2022-05-22T00:00:00+00:00" itemprop="datePublished"><i class="fa fa-calendar"></i> May 22, 2022
</time>
<span class="post-reading-time left-vsplit"><i class="fa fa-clock-o"></i> About 1 min</span>
</p>
<div class="post-tags">
<a class="post-tag" href="/tags.html#automatizace">#automatizace</a><a class="post-tag" href="/tags.html#technologie">#technologie</a>
</div></header>
<article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">
<div class="post-content e-content" itemprop="articleBody">
<p>Roboti nám brzo vezmou práci, ale mně to (prozatím) nevadí. Já nechávám robůtky pracovat za mě a ulehčovat mi práci. A vy byste měli taky! Pokud teda programujete, jinak nevím.</p>
<p>Nedávno jsem objevil krásy zvané GitHub Actions a musím říct, že je to opravdu radost. Nikdy předtím jsem nedokázal pochopit jejich praktičnost, než jsem pracoval na <a href="https://github.com/hernikplays/opencanteen">OpenCanteen</a>. Sestavovat, podepisovat a nahrávat mě opravdu nebavilo a ještě s mým pomalým PC v kombinaci s pomalým internetem to nešlo zrovna rychle. Pak jsem si vzpomněl na GitHub Actions. Místo toho, abych dělal cokoliv produktivního, jsem strávil celé odpoledne nastavováním Actions, aby mi při novém tagu automaticky sestavil a publikoval vydání aplikace do Google Play.</p>
<p>Ta první část šla skvěle, avšak nahrávání do Google Play bylo o něco složitější, dokud jsem neobjevil hotové a, prozatím bezplatné, řešení <a href="https://codemagic.io/start/">CodeMagic</a>.</p>
<p>Jednoduše jsem napojil repozitář, nastavil podepisovací a nahrávací údaje a všechno hned jelo! Byla to radost pro někoho tak líného jako jsem já. I přesto, že jsem sám reálně nic neudělal, cítil jsem, že jsem dosáhl něčeho úžasného.</p>
<p>A určitě to lze dotáhnout ještě dál, už teď používám Actions pro automatickou analýzu kódu, a kdybych si vytvořil testy tak by mi to určitě i otestovalo celou aplikaci.</p>
<p>Pak jsem si řekl, že by možná mohl někdo chtít do mé aplikace přispět svým kódem. Protože chci v tom mít pořádek, hned jsem začal projíždět GitHub Marketplace pro nějaké akce na pull requesty. Hned jsem jich několik objevil.</p>
<p>Velice jsem ocenil akci, která mi automaticky přidala labely podle souboru, který byl v PR upraven.</p>
<p>Určitě nepotřebujete nutně automatizovat všechno, pokud máte např. soukromý či malý projekt. Nicméně si to můžete aspoň otestovat a případně využít v budoucnu tak se do toho pusťte! Automatizovat můžete všechno možné. Určitě budete mít dobrý pocit, když se vaše akce spustí a úspěšně se dokončí.</p>
</div>
</article>
<div class="post-nav">
<span></span><a class="next" href="/vychyt%C3%A1vky/2022/05/31/codespaces.html" title="GitHub Codespaces aneb VS Code na VPS">GitHub Codespaces aneb VS Code na...</a>
</div>
<div class="post-related">
<div>Related Articles</div>
<ul>
<li><a class="post-link" href="/programov%C3%A1n%C3%AD/2022/05/22/automatizace.html" title="GitHub Codespaces aneb VS Code na VPS">Automatizace, automatizace, automatizace</a></li>
<li><a class="post-link" href="/tutori%C3%A1l/2022/10/22/rpi-arch.html" title="GitHub Codespaces aneb VS Code na VPS">Instalujeme Arch Linux ARM na Raspberry Pi 3</a></li>
<li><a class="post-link" href="/vychyt%C3%A1vky/2022/05/31/codespaces.html" title="GitHub Codespaces aneb VS Code na VPS">GitHub Codespaces aneb VS Code na VPS</a></li>
<li><a class="post-link" href="/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn.html" title="GitHub Codespaces aneb VS Code na VPS">NordVPN - Jste opravdu v takovém nebezpečí?</a></li>
</ul>
</div>
<div class="post-comments"> <div id="gitment_thread" class="giscus"></div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/theme-next/theme-next-gitment@1/default.css">
<script src="https://cdn.jsdelivr.net/gh/theme-next/theme-next-gitment@1/gitment.browser.js"></script>
<script src="https://giscus.app/client.js" data-repo="hernikplays/blog" data-repo-id="R_kgDOHr2B6w" data-category="General" data-category-id="DIC_kwDOHr2B684CSIhA" data-mapping="pathname" data-strict="0" data-reactions-enabled="1" data-emit-metadata="0" data-input-position="top" data-theme="transparent_dark" data-lang="en" data-loading="lazy" crossorigin="anonymous" async>
</script>
</div></section>
</div>
</section>
<section class="sidebar" style="margin-left: 15px;">
<!-- Get sidebar items --></section>
</div>
</div>
</main><footer class="site-footer h-card">
<data class="u-url" href="/"></data>
<div class="wrapper">
<div class="site-footer-inner">
<div>Copyright © 2021-2022 hernikplays</div>
<div>Powered by <a title="Jekyll is a simple, blog-aware, static site
generator." href="https://jekyllrb.com/">Jekyll</a> &amp; <a title="Yat, yet
another theme." href="https://github.com/jeffreytse/jekyll-theme-yat">Yat Theme</a>.</div>
<div><a rel="me" href="https://social.linux.pizza/@hernik">Mastodon</a></div>
<div class="footer-col rss-subscribe">Subscribe <a href="/feed.xml">via RSS</a>
</div>
</div>
</div>
</footer>
</body>
</html>

1
robots.txt Normal file
View file

@ -0,0 +1 @@
Sitemap: https://caras.cafe/sitemap.xml

34
sitemap.xml Normal file
View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://caras.cafe/programov%C3%A1n%C3%AD/2022/05/22/automatizace.html</loc>
<lastmod>2022-05-22T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://caras.cafe/vychyt%C3%A1vky/2022/05/31/codespaces.html</loc>
<lastmod>2022-05-31T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://caras.cafe/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn.html</loc>
<lastmod>2022-07-19T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://caras.cafe/tutori%C3%A1l/2022/10/22/rpi-arch.html</loc>
<lastmod>2022-10-22T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://caras.cafe/about.html</loc>
</url>
<url>
<loc>https://caras.cafe/archives.html</loc>
</url>
<url>
<loc>https://caras.cafe/categories.html</loc>
</url>
<url>
<loc>https://caras.cafe/</loc>
</url>
<url>
<loc>https://caras.cafe/tags.html</loc>
</url>
</urlset>

917
tags.html
View file

@ -1,4 +1,913 @@
---
layout: tags
title: Tags
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="google-translate-customization" content="108d9124921d80c3-80e20d618ff053c8-g4f02ec6f3dba68b7-c">
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>Tags | Matyáš Caras</title>
<meta name="generator" content="Jekyll v4.3.1">
<meta property="og:title" content="Tags">
<meta name="author" content="hernikplays">
<meta property="og:locale" content="en_US">
<meta name="description" content="Welcome to my website/blog, full of weird stuff written by yours truly.">
<meta property="og:description" content="Welcome to my website/blog, full of weird stuff written by yours truly.">
<link rel="canonical" href="https://caras.cafe/tags.html">
<meta property="og:url" content="https://caras.cafe/tags.html">
<meta property="og:site_name" content="Matyáš Caras">
<meta property="og:type" content="website">
<meta name="twitter:card" content="summary">
<meta property="twitter:title" content="Tags">
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"WebPage","author":{"@type":"Person","name":"hernikplays"},"description":"Welcome to my website/blog, full of weird stuff written by yours truly.","headline":"Tags","url":"https://caras.cafe/tags.html"}</script>
<!-- End Jekyll SEO tag -->
<link rel="shortcut icon" href="">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/typeface-noto-sans@0.0.72/index.min.css">
<link rel="stylesheet" href="/assets/css/main.css">
<script src="/assets/js/main.js"></script><link type="application/atom+xml" rel="alternate" href="https://caras.cafe/feed.xml" title="Matyáš Caras">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js"></script>
<!-- and it's easy to individually load additional languages -->
<script charset="UTF-8" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/languages/go.min.js"></script>
<script>
// Init highlight js
document.addEventListener('DOMContentLoaded', function(event) {
var els = document.querySelectorAll('pre code')
function addLangData(block) {
var outer = block.parentElement.parentElement.parentElement;
var lang = block.getAttribute('data-lang');
for (var i = 0; i < outer.classList.length; i++) {
var cls = outer.classList[i];
if (cls.startsWith('language-')) {
lang = cls;
break;
}
}
if (!lang) {
cls = block.getAttribute('class');
lang = cls ? cls.replace('hljs ', '') : '';
}
if (lang.startsWith('language-')) {
lang = lang.substr(9);
}
block.setAttribute('class', 'hljs ' + lang);
block.parentNode.setAttribute('data-lang', lang);
}
function addBadge(block) {
var enabled = ('true' || 'true').toLowerCase();
if (enabled == 'true') {
var pre = block.parentElement;
pre.classList.add('badge');
}
}
function handle(block) {
addLangData(block);
addBadge(block)
hljs.highlightBlock(block);
}
for (var i = 0; i < els.length; i++) {
var el = els[i];
handle(el);
}
});
</script>
<style>
/* code language badge */
pre.badge::before {
content: attr(data-lang);
color: #fff;
background-color: #ff4e00;
padding: 0 .5em;
border-radius: 0 2px;
text-transform: uppercase;
text-align: center;
min-width: 32px;
display: inline-block;
position: absolute;
right: 0;
}
/* fix wrong badge display for firefox browser */
code > table pre::before {
display: none;
}
</style>
</head>
<body>
<header class="site-header " role="banner">
<div class="wrapper">
<div class="site-header-inner">
<span class="site-brand"><a class="site-brand-inner" rel="author" href="/">
<img class="site-favicon" title="Matyáš Caras" src="" onerror="this.style.display='none'">
Matyáš Caras
</a>
</span><nav class="site-nav">
<input type="checkbox" id="nav-trigger" class="nav-trigger">
<label for="nav-trigger">
<span class="menu-icon">
<svg viewbox="0 0 18 15" width="18px" height="15px">
<path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"></path>
</svg>
</span>
</label>
<div class="trigger">
<a class="page-link" href="/about.html">ABOUT</a><a class="page-link" href="/archives.html">ARCHIVES</a><a class="page-link" href="/categories.html">CATEGORIES</a><a class="page-link" href="/">HOME</a><a class="page-link" href="/tags.html">TAGS</a>
</div>
</nav>
</div>
</div>
</header>
<script>
function initHeader() {
var lastScrollY = getScrollPos().y;
var documentElement = document.documentElement;
function storeScrollData() {
var y = getScrollPos().y;var scrollStatus = "";
if (y <= 0) {
scrollStatus = "top";
} else if ((window.innerHeight + y) >= document.body.offsetHeight) {
scrollStatus = "bottom";
} else {
var isScrollDown = (y - lastScrollY > 0) ? true : false;
scrollStatus = isScrollDown ? "down" : "up";
}
lastScrollY = y;
documentElement.setAttribute("data-scroll-status", scrollStatus);
}
window.addEventListener('scroll', function(e) {
storeScrollData();
});
storeScrollData();
}
document.addEventListener('DOMContentLoaded', initHeader);
</script>
<script>
function hashLocate(hashValue) {
hashValue = hashValue.replace(/^.*#h-/, '');
hashValue = decodeURIComponent(hashValue);
var element = document.getElementById(hashValue);
if (!element) {
return;
}
var header = document.querySelector('header.site-header');
var headerRect = header.getBoundingClientRect();
var headerTop = Math.floor(headerRect.top);
var headerHeight = Math.floor(headerRect.height);
var scrollPos = getScrollPos();
var offsetY = element.offsetTop - (headerTop + headerHeight + 20);
if (offsetY == scrollPos.y) {
return;
}
if (headerTop == 0 && offsetY > scrollPos.y) {
offsetY += headerHeight + 2;
} else if (headerTop < 0 && offsetY < scrollPos.y) {
offsetY -= headerHeight - 2;
}
smoothScrollTo(offsetY);
}
// The first event occurred
window.addEventListener('load', function(event) {
if (window.location.hash) {
hashLocate(window.location.hash);
}
});
// The first event occurred
window.addEventListener('click', function(event) {
if (event.target.tagName.toLowerCase() == 'a') {
hashLocate(event.target.getAttribute('href'));
}
});
</script>
<div class="theme-toggle">
<input type="checkbox" id="theme-switch">
<label for="theme-switch">
<div class="toggle"></div>
<div class="names">
<p class="light">Light</p>
<p class="dark">Dark</p>
</div>
</label>
</div>
<script>
(function() {
var sw = document.getElementById('theme-switch');
var html = document.getElementsByTagName('html')[0];
var nightModeOption = ('auto' || 'auto').toLowerCase();
var storage = nightModeOption === 'manual'
? localStorage
: sessionStorage;
var themeData = loadThemeData();
function saveThemeData(data) {
storage.setItem('theme', JSON.stringify(data));
}
function loadThemeData() {
var data = storage.getItem('theme');
try {
data = JSON.parse(data ? data : '');
} catch(e) {
data = { nightShift: undefined, autoToggleAt: 0 };
saveThemeData(data);
}
return data;
}
function handleThemeToggle(nightShift) {
themeData.nightShift = nightShift;
saveThemeData(themeData);
html.dataset.theme = nightShift ? 'dark' : 'light';
setTimeout(function() {
sw.checked = nightShift ? true : false;
}, 50);
}
function autoThemeToggle() {
// Next time point of theme toggle
var now = new Date();
var toggleAt = new Date();
var hours = now.getHours();
var nightShift = hours >= 19 || hours <=7;
if (nightShift) {
if (hours > 7) {
toggleAt.setDate(toggleAt.getDate() + 1);
}
toggleAt.setHours(7);
} else {
toggleAt.setHours(19);
}
toggleAt.setMinutes(0);
toggleAt.setSeconds(0);
toggleAt.setMilliseconds(0)
var delay = toggleAt.getTime() - now.getTime();
// auto toggle theme mode
setTimeout(function() {
handleThemeToggle(!nightShift);
}, delay);
return {
nightShift: nightShift,
toggleAt: toggleAt.getTime()
};
}
// Listen the theme toggle event
sw.addEventListener('change', function(event) {
handleThemeToggle(event.target.checked);
});
if (nightModeOption == 'auto') {
var data = autoThemeToggle();
// Toggle theme by local setting
if (data.toggleAt > themeData.autoToggleAt) {
themeData.autoToggleAt = data.toggleAt;
handleThemeToggle(data.nightShift);
} else {
handleThemeToggle(themeData.nightShift);
}
} else if (nightModeOption == 'manual') {
handleThemeToggle(themeData.nightShift);
} else {
var nightShift = themeData.nightShift;
if (nightShift === undefined) {
nightShift = nightModeOption === 'on';
}
handleThemeToggle(nightShift);
}
})();
</script>
<div id="click-to-top" class="click-to-top">
<i class="fa fa-arrow-up"></i>
</div>
<script>
(function () {
const clickToTop = document.getElementById('click-to-top');
window.addEventListener('scroll', () => {
if (window.scrollY > 100) {
clickToTop.classList.add('show')
}else {
clickToTop.classList.remove('show')
}
});
clickToTop.addEventListener('click', () => {
window.smoothScrollTo(0);
});
})();
</script>
<main class="page-content" aria-label="Content">
<div class="wrapper">
<div class="framework">
<section class="main">
<div class="page-segments">
<ul class="page-segments-list">
<h2 id="arch" class="segment-name">arch</h2>
<li>
<span class="post-meta">Oct 22, 2022</span>
<span>
<a class="post-link" href="/tutori%C3%A1l/2022/10/22/rpi-arch.html">
Instalujeme Arch Linux ARM na Raspberry Pi 3
</a>
</span>
</li>
<h2 id="automatizace" class="segment-name">automatizace</h2>
<li>
<span class="post-meta">May 22, 2022</span>
<span>
<a class="post-link" href="/programov%C3%A1n%C3%AD/2022/05/22/automatizace.html">
Automatizace, automatizace, automatizace
</a>
</span>
</li>
<h2 id="github" class="segment-name">github</h2>
<li>
<span class="post-meta">May 31, 2022</span>
<span>
<a class="post-link" href="/vychyt%C3%A1vky/2022/05/31/codespaces.html">
GitHub Codespaces aneb VS Code na VPS
</a>
</span>
</li>
<h2 id="návod" class="segment-name">návod</h2>
<li>
<span class="post-meta">Oct 22, 2022</span>
<span>
<a class="post-link" href="/tutori%C3%A1l/2022/10/22/rpi-arch.html">
Instalujeme Arch Linux ARM na Raspberry Pi 3
</a>
</span>
</li>
<h2 id="reklamy" class="segment-name">reklamy</h2>
<li>
<span class="post-meta">Jul 19, 2022</span>
<span>
<a class="post-link" href="/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn.html">
NordVPN - Jste opravdu v takovém nebezpečí?
</a>
</span>
</li>
<h2 id="rpi" class="segment-name">rpi</h2>
<li>
<span class="post-meta">Oct 22, 2022</span>
<span>
<a class="post-link" href="/tutori%C3%A1l/2022/10/22/rpi-arch.html">
Instalujeme Arch Linux ARM na Raspberry Pi 3
</a>
</span>
</li>
<h2 id="technologie" class="segment-name">technologie</h2>
<li>
<span class="post-meta">May 22, 2022</span>
<span>
<a class="post-link" href="/programov%C3%A1n%C3%AD/2022/05/22/automatizace.html">
Automatizace, automatizace, automatizace
</a>
</span>
</li>
<h2 id="vpn" class="segment-name">vpn</h2>
<li>
<span class="post-meta">Jul 19, 2022</span>
<span>
<a class="post-link" href="/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn.html">
NordVPN - Jste opravdu v takovém nebezpečí?
</a>
</span>
</li>
<h2 id="vps" class="segment-name">vps</h2>
<li>
<span class="post-meta">May 31, 2022</span>
<span>
<a class="post-link" href="/vychyt%C3%A1vky/2022/05/31/codespaces.html">
GitHub Codespaces aneb VS Code na VPS
</a>
</span>
</li>
<h2 id="youtube" class="segment-name">youtube</h2>
<li>
<span class="post-meta">Jul 19, 2022</span>
<span>
<a class="post-link" href="/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn.html">
NordVPN - Jste opravdu v takovém nebezpečí?
</a>
</span>
</li>
</ul>
</div>
</section>
<section class="sidebar" style="margin-left: 15px;">
<!-- Get sidebar items -->
<div class="common-list">
<ul>
<li>
<a href="/index.html">
All<span>4</span>
</a>
</li>
<li>
<a href="/tags.html#h-arch">
arch <span>1</span>
</a>
</li>
<li>
<a href="/tags.html#h-automatizace">
automatizace <span>1</span>
</a>
</li>
<li>
<a href="/tags.html#h-github">
github <span>1</span>
</a>
</li>
<li>
<a href="/tags.html#h-n%C3%A1vod">
návod <span>1</span>
</a>
</li>
<li>
<a href="/tags.html#h-reklamy">
reklamy <span>1</span>
</a>
</li>
<li>
<a href="/tags.html#h-rpi">
rpi <span>1</span>
</a>
</li>
<li>
<a href="/tags.html#h-technologie">
technologie <span>1</span>
</a>
</li>
<li>
<a href="/tags.html#h-vpn">
vpn <span>1</span>
</a>
</li>
<li>
<a href="/tags.html#h-vps">
vps <span>1</span>
</a>
</li>
<li>
<a href="/tags.html#h-youtube">
youtube <span>1</span>
</a>
</li>
</ul>
</div>
</section>
</div>
</div>
</main><footer class="site-footer h-card">
<data class="u-url" href="/"></data>
<div class="wrapper">
<div class="site-footer-inner">
<div>Copyright © 2021-2022 hernikplays</div>
<div>Powered by <a title="Jekyll is a simple, blog-aware, static site
generator." href="https://jekyllrb.com/">Jekyll</a> &amp; <a title="Yat, yet
another theme." href="https://github.com/jeffreytse/jekyll-theme-yat">Yat Theme</a>.</div>
<div><a rel="me" href="https://social.linux.pizza/@hernik">Mastodon</a></div>
<div class="footer-col rss-subscribe">Subscribe <a href="/feed.xml">via RSS</a>
</div>
</div>
</div>
</footer>
</body>
</html>

View file

@ -0,0 +1,827 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="google-translate-customization" content="108d9124921d80c3-80e20d618ff053c8-g4f02ec6f3dba68b7-c">
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>Instalujeme Arch Linux ARM na Raspberry Pi 3 | Matyáš Caras</title>
<meta name="generator" content="Jekyll v4.3.1">
<meta property="og:title" content="Instalujeme Arch Linux ARM na Raspberry Pi 3">
<meta name="author" content="hernikplays">
<meta property="og:locale" content="en_US">
<meta name="description" content="Welcome to my website/blog, full of weird stuff written by yours truly.">
<meta property="og:description" content="Welcome to my website/blog, full of weird stuff written by yours truly.">
<link rel="canonical" href="https://caras.cafe/tutori%C3%A1l/2022/10/22/rpi-arch.html">
<meta property="og:url" content="https://caras.cafe/tutori%C3%A1l/2022/10/22/rpi-arch.html">
<meta property="og:site_name" content="Matyáš Caras">
<meta property="og:type" content="article">
<meta property="article:published_time" content="2022-10-22T00:00:00+00:00">
<meta name="twitter:card" content="summary">
<meta property="twitter:title" content="Instalujeme Arch Linux ARM na Raspberry Pi 3">
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"BlogPosting","author":{"@type":"Person","name":"hernikplays"},"dateModified":"2022-10-22T00:00:00+00:00","datePublished":"2022-10-22T00:00:00+00:00","description":"Welcome to my website/blog, full of weird stuff written by yours truly.","headline":"Instalujeme Arch Linux ARM na Raspberry Pi 3","mainEntityOfPage":{"@type":"WebPage","@id":"https://caras.cafe/tutori%C3%A1l/2022/10/22/rpi-arch.html"},"url":"https://caras.cafe/tutori%C3%A1l/2022/10/22/rpi-arch.html"}</script>
<!-- End Jekyll SEO tag -->
<link rel="shortcut icon" href="">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/typeface-noto-sans@0.0.72/index.min.css">
<link rel="stylesheet" href="/assets/css/main.css">
<script src="/assets/js/main.js"></script><link type="application/atom+xml" rel="alternate" href="https://caras.cafe/feed.xml" title="Matyáš Caras">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js"></script>
<!-- and it's easy to individually load additional languages -->
<script charset="UTF-8" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/languages/go.min.js"></script>
<script>
// Init highlight js
document.addEventListener('DOMContentLoaded', function(event) {
var els = document.querySelectorAll('pre code')
function addLangData(block) {
var outer = block.parentElement.parentElement.parentElement;
var lang = block.getAttribute('data-lang');
for (var i = 0; i < outer.classList.length; i++) {
var cls = outer.classList[i];
if (cls.startsWith('language-')) {
lang = cls;
break;
}
}
if (!lang) {
cls = block.getAttribute('class');
lang = cls ? cls.replace('hljs ', '') : '';
}
if (lang.startsWith('language-')) {
lang = lang.substr(9);
}
block.setAttribute('class', 'hljs ' + lang);
block.parentNode.setAttribute('data-lang', lang);
}
function addBadge(block) {
var enabled = ('true' || 'true').toLowerCase();
if (enabled == 'true') {
var pre = block.parentElement;
pre.classList.add('badge');
}
}
function handle(block) {
addLangData(block);
addBadge(block)
hljs.highlightBlock(block);
}
for (var i = 0; i < els.length; i++) {
var el = els[i];
handle(el);
}
});
</script>
<style>
/* code language badge */
pre.badge::before {
content: attr(data-lang);
color: #fff;
background-color: #ff4e00;
padding: 0 .5em;
border-radius: 0 2px;
text-transform: uppercase;
text-align: center;
min-width: 32px;
display: inline-block;
position: absolute;
right: 0;
}
/* fix wrong badge display for firefox browser */
code > table pre::before {
display: none;
}
</style>
</head>
<body>
<header class="site-header " role="banner">
<div class="wrapper">
<div class="site-header-inner">
<span class="site-brand"><a class="site-brand-inner" rel="author" href="/">
<img class="site-favicon" title="Matyáš Caras" src="" onerror="this.style.display='none'">
Matyáš Caras
</a>
</span><nav class="site-nav">
<input type="checkbox" id="nav-trigger" class="nav-trigger">
<label for="nav-trigger">
<span class="menu-icon">
<svg viewbox="0 0 18 15" width="18px" height="15px">
<path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"></path>
</svg>
</span>
</label>
<div class="trigger">
<a class="page-link" href="/about.html">ABOUT</a><a class="page-link" href="/archives.html">ARCHIVES</a><a class="page-link" href="/categories.html">CATEGORIES</a><a class="page-link" href="/">HOME</a><a class="page-link" href="/tags.html">TAGS</a>
</div>
</nav>
</div>
</div>
</header>
<script>
function initHeader() {
var lastScrollY = getScrollPos().y;
var documentElement = document.documentElement;
function storeScrollData() {
var y = getScrollPos().y;var scrollStatus = "";
if (y <= 0) {
scrollStatus = "top";
} else if ((window.innerHeight + y) >= document.body.offsetHeight) {
scrollStatus = "bottom";
} else {
var isScrollDown = (y - lastScrollY > 0) ? true : false;
scrollStatus = isScrollDown ? "down" : "up";
}
lastScrollY = y;
documentElement.setAttribute("data-scroll-status", scrollStatus);
}
window.addEventListener('scroll', function(e) {
storeScrollData();
});
storeScrollData();
}
document.addEventListener('DOMContentLoaded', initHeader);
</script>
<script>
function hashLocate(hashValue) {
hashValue = hashValue.replace(/^.*#h-/, '');
hashValue = decodeURIComponent(hashValue);
var element = document.getElementById(hashValue);
if (!element) {
return;
}
var header = document.querySelector('header.site-header');
var headerRect = header.getBoundingClientRect();
var headerTop = Math.floor(headerRect.top);
var headerHeight = Math.floor(headerRect.height);
var scrollPos = getScrollPos();
var offsetY = element.offsetTop - (headerTop + headerHeight + 20);
if (offsetY == scrollPos.y) {
return;
}
if (headerTop == 0 && offsetY > scrollPos.y) {
offsetY += headerHeight + 2;
} else if (headerTop < 0 && offsetY < scrollPos.y) {
offsetY -= headerHeight - 2;
}
smoothScrollTo(offsetY);
}
// The first event occurred
window.addEventListener('load', function(event) {
if (window.location.hash) {
hashLocate(window.location.hash);
}
});
// The first event occurred
window.addEventListener('click', function(event) {
if (event.target.tagName.toLowerCase() == 'a') {
hashLocate(event.target.getAttribute('href'));
}
});
</script>
<div class="theme-toggle">
<input type="checkbox" id="theme-switch">
<label for="theme-switch">
<div class="toggle"></div>
<div class="names">
<p class="light">Light</p>
<p class="dark">Dark</p>
</div>
</label>
</div>
<script>
(function() {
var sw = document.getElementById('theme-switch');
var html = document.getElementsByTagName('html')[0];
var nightModeOption = ('auto' || 'auto').toLowerCase();
var storage = nightModeOption === 'manual'
? localStorage
: sessionStorage;
var themeData = loadThemeData();
function saveThemeData(data) {
storage.setItem('theme', JSON.stringify(data));
}
function loadThemeData() {
var data = storage.getItem('theme');
try {
data = JSON.parse(data ? data : '');
} catch(e) {
data = { nightShift: undefined, autoToggleAt: 0 };
saveThemeData(data);
}
return data;
}
function handleThemeToggle(nightShift) {
themeData.nightShift = nightShift;
saveThemeData(themeData);
html.dataset.theme = nightShift ? 'dark' : 'light';
setTimeout(function() {
sw.checked = nightShift ? true : false;
}, 50);
}
function autoThemeToggle() {
// Next time point of theme toggle
var now = new Date();
var toggleAt = new Date();
var hours = now.getHours();
var nightShift = hours >= 19 || hours <=7;
if (nightShift) {
if (hours > 7) {
toggleAt.setDate(toggleAt.getDate() + 1);
}
toggleAt.setHours(7);
} else {
toggleAt.setHours(19);
}
toggleAt.setMinutes(0);
toggleAt.setSeconds(0);
toggleAt.setMilliseconds(0)
var delay = toggleAt.getTime() - now.getTime();
// auto toggle theme mode
setTimeout(function() {
handleThemeToggle(!nightShift);
}, delay);
return {
nightShift: nightShift,
toggleAt: toggleAt.getTime()
};
}
// Listen the theme toggle event
sw.addEventListener('change', function(event) {
handleThemeToggle(event.target.checked);
});
if (nightModeOption == 'auto') {
var data = autoThemeToggle();
// Toggle theme by local setting
if (data.toggleAt > themeData.autoToggleAt) {
themeData.autoToggleAt = data.toggleAt;
handleThemeToggle(data.nightShift);
} else {
handleThemeToggle(themeData.nightShift);
}
} else if (nightModeOption == 'manual') {
handleThemeToggle(themeData.nightShift);
} else {
var nightShift = themeData.nightShift;
if (nightShift === undefined) {
nightShift = nightModeOption === 'on';
}
handleThemeToggle(nightShift);
}
})();
</script>
<div id="click-to-top" class="click-to-top">
<i class="fa fa-arrow-up"></i>
</div>
<script>
(function () {
const clickToTop = document.getElementById('click-to-top');
window.addEventListener('scroll', () => {
if (window.scrollY > 100) {
clickToTop.classList.add('show')
}else {
clickToTop.classList.remove('show')
}
});
clickToTop.addEventListener('click', () => {
window.smoothScrollTo(0);
});
})();
</script>
<main class="page-content" aria-label="Content">
<div class="wrapper">
<div class="framework">
<section class="main">
<div class="post">
<section>
<header class="post-header">
<h1 class="post-title p-name" itemprop="name headline">Instalujeme Arch Linux ARM na Raspberry Pi 3</h1>
<h2 class="post-subtitle">Protože proč ne</h2>
<p class="post-meta">
<time class="dt-published" datetime="2022-10-22T00:00:00+00:00" itemprop="datePublished"><i class="fa fa-calendar"></i> Oct 22, 2022
</time>
<span class="post-reading-time left-vsplit"><i class="fa fa-clock-o"></i> About 6 mins</span>
</p>
<div class="post-tags">
<a class="post-tag" href="/tags.html#n%C3%A1vod">#návod</a><a class="post-tag" href="/tags.html#rpi">#rpi</a><a class="post-tag" href="/tags.html#arch">#arch</a>
</div></header>
<article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">
<div class="post-content e-content" itemprop="articleBody">
<p><img src="https://archlinuxarm.org/public/images/alarm.png" alt="Arch Linux ARM logo"></p>
<p>Raspbian OS už je ohraný. Pojďme si nainstalovat <a href="https://archlinuxarm.org/platforms/armv8/broadcom/raspberry-pi-3">ARM verzi Arch Linuxu</a> na Raspberry Pi 3. Proces je relativně prostý.</p>
<h1 id="připravujeme-sd-kartu">Připravujeme SD kartu</h1>
<p>Nejdřív je nutné SD kartu naformátovat a rozdělit oddíly. Můžete to udělat svým oblíbeným způsobem, já použiji GUI nástroj GParted.</p>
<p>Odstraníme všechny oddíly skrz kontextové menu pravého kliknutí a potvrzení fajfkou.</p>
<p><img src="/assets/images/rpi-arch/01.png" alt="Odstraněné oddíly v GParted"></p>
<p>Následně vytvoříme jeden FAT32 oddíl, který bude sloužit jako bootovací. Bude stačit 128 MiB.</p>
<p><img src="/assets/images/rpi-arch/02.png" alt="Vytváření FAT32 oddílu v GParted"></p>
<p>Druhý oddíl bude náš systémový, který bude ext4.</p>
<p><img src="/assets/images/rpi-arch/03.png" alt="Vytváření ext4 oddílu v GParted"></p>
<p>Jakmile fajfkou potvrdíme a necháme oddíly vytvořit, můžete je ještě zformátovat, nicméně je nejdůležitější nastavit <code class="language-plaintext highlighter-rouge">boot</code> příznak na našem boot oddílu skrz kontextové menu.</p>
<p><img src="/assets/images/rpi-arch/04.png" alt="Výběr příznaků v GParted"></p>
<p>Tak je všechno hotovo v GParted.</p>
<h1 id="přesouváme-systém">Přesouváme systém</h1>
<p>Dále připojíme naše oddíly podle jejich identifikátoru a čísla připojíme.</p>
<p>Nejdřív si vytvoříme složky, <code class="language-plaintext highlighter-rouge">sudo mkdir -p /mnt/archpi/{root,boot}</code> nám vytvoří složky <code class="language-plaintext highlighter-rouge">root</code> a <code class="language-plaintext highlighter-rouge">boot</code> pro naše oddíly.</p>
<p>Dále příkazem <code class="language-plaintext highlighter-rouge">sudo mount /dev/sdc1 /mnt/archpi/root</code> připojíme náš FAT32 bootovácí oddíl (<strong>Označení <code class="language-plaintext highlighter-rouge">sdc1</code> se u vás může lišit, podívejte se do GPartedu nebo skrz příkaz <code class="language-plaintext highlighter-rouge">lsblk</code> na označení jednotlivých oddílů</strong>) a příkazem <code class="language-plaintext highlighter-rouge">sudo mount /dev/sdc2 /mnt/archpi/boot</code> připojíme systémový oddíl.</p>
<p>Dle oficiální <a href="https://archlinuxarm.org/platforms/armv8/broadcom/raspberry-pi-3">dokumentace</a> se další proces má dělat skrz root uživatele, takže se přepneme příkazem <code class="language-plaintext highlighter-rouge">sudo su</code>.</p>
<p>Příkazem <code class="language-plaintext highlighter-rouge">wget http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-armv7-latest.tar.gz</code> stáhneme archiv a příkazem <code class="language-plaintext highlighter-rouge">tar -xf ArchLinuxARM-rpi-armv7-latest.tar.gz -C /mnt/archpi/root</code> ho rozbalíme.</p>
<p>Pak musíme přesunout bootovací soubory do bootovacího oddílu: <code class="language-plaintext highlighter-rouge">mv /mnt/archpi/root/boot/* boot</code> a tím jsme hotovi, stačí oddíly odpojit příkazem <code class="language-plaintext highlighter-rouge">umount /mnt/archpi/root</code> a <code class="language-plaintext highlighter-rouge">umount /mnt/archpi/boot</code>. Jakmile se příkazy dokončí, můžete SD kartu vložit do RPi a zapnout.</p>
<p>Výchozí jméno a zároveň heslo uživatele je <code class="language-plaintext highlighter-rouge">alarm</code> a roota <code class="language-plaintext highlighter-rouge">root</code>. Než bude systém nastavený, doporučuji použít <code class="language-plaintext highlighter-rouge">root</code> účet.</p>
<h1 id="připojení-k-wi-fi-síti">Připojení k Wi-Fi síti</h1>
<p><em>Pokud používáte kabelové připojení, tak můžete přeskočit</em>
Nyní se připojíme skrz terminál k Wi-Fi síti. Předpokládám, že název (SSID) sítě a heslo znáte a že zabezpečení je WPA2 Personal. Jinak si můžete prohlédnout <a href="https://wiki.archlinux.org/title/Network_configuration/Wireless">Arch Wiki</a> pro více návodů.</p>
<p>Příkazem <code class="language-plaintext highlighter-rouge">iw dev</code> zjistíte název vašeho interfacu (např. já mám <code class="language-plaintext highlighter-rouge">wlan0</code>). Zapneme ho pomocí <code class="language-plaintext highlighter-rouge">ip link wlan0 up</code> (místo <code class="language-plaintext highlighter-rouge">wlan0</code> tedy použijte váš název interfacu).</p>
<p>Dále se tedy připojíme k nějaké Wi-Fi síti. Nejdřív musíme vytvořit konfigurační soubor pro <code class="language-plaintext highlighter-rouge">wpa_supplicant</code>, který slouží jako <a href="https://cs.wikipedia.org/wiki/Suplikant">suplikant</a> s podporou WPA, WPA2 a WPA3.</p>
<p>Pomocí příkazu <code class="language-plaintext highlighter-rouge">nano /etc/wpa_supplicant/wpa_supplicant.conf</code> vstoupíme do editace konfiguračního souboru. Do něj vložíme následující dva řádky:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ctrl_interface=/run/wpa_supplicant
update_config=1
</code></pre></div></div>
<p>Klávesovou zkratkou <code class="language-plaintext highlighter-rouge">Ctrl+X</code>, zadáním <code class="language-plaintext highlighter-rouge">y</code> a potvrzením enterem uložíme soubor a opustíme editaci. wpa_supplicant teď můžeme spustit příkazem <code class="language-plaintext highlighter-rouge">wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf</code>.</p>
<p>S běžícím wpa_supplicant můžeme použít příkaz <code class="language-plaintext highlighter-rouge">wpa_cli</code>, kde můžeme konfigurovat síť.</p>
<p>Sítě zde můžete hledat příkazem <a href="https://wiki.archlinux.org/title/Wpa_supplicant#Connecting_with_wpa_cli"><code class="language-plaintext highlighter-rouge">scan</code></a>, následováný <code class="language-plaintext highlighter-rouge">scan_results</code>.</p>
<p>Pro přidání sítě použijeme příkaz <code class="language-plaintext highlighter-rouge">add_network</code>. Terminál vrátí <code class="language-plaintext highlighter-rouge">0</code>, což je ID sítě, které můžeme konfigurovat. Příkazem <code class="language-plaintext highlighter-rouge">set_network 0 ssid "MYSSID"</code> nastavíme SSID (název) sítě na <code class="language-plaintext highlighter-rouge">MYSSID</code>. Příkazem <code class="language-plaintext highlighter-rouge">set_network 0 psk "passphrase"</code> nastavíme heslo na <code class="language-plaintext highlighter-rouge">passphrase</code>. Jakmile je nastaveno, můžeme povolit síť pomocí <code class="language-plaintext highlighter-rouge">enable_network 0</code>. Konfiguraci uložíme příkazem <code class="language-plaintext highlighter-rouge">save_config</code> a opustíme pomocí <code class="language-plaintext highlighter-rouge">quit</code>.</p>
<p>Jelikož ale právě teď nemáme IP adresu, musíme nastavit službu DHCP (pokud ji samozřejmě váš router má). Stačí zapnout službu <code class="language-plaintext highlighter-rouge">dhcpcd</code> pomocí příkazu <code class="language-plaintext highlighter-rouge">systemctl enable dhcpcd</code>. Abychom při každém zapnutí nemuseli síť manuálně zapínat, můžeme do <code class="language-plaintext highlighter-rouge">dhcpcd</code> přidat <a href="https://wiki.archlinux.org/title/Dhcpcd#10-wpa_supplicant">hook</a>, který ji automaticky zapne, stačí použít <code class="language-plaintext highlighter-rouge">ln -s /usr/share/dhcpcd/hooks/10-wpa_supplicant /usr/lib/dhcpcd/dhcpcd-hooks/</code>.</p>
<p>V tomto stádiu doporučuji restartovat příkazem <code class="language-plaintext highlighter-rouge">reboot</code>.</p>
<h1 id="nastavujeme-správce-balíků">Nastavujeme správce balíků</h1>
<p>Aktuálně bychom měli mít funkční síť, nicméně je potřeba pár dalších příkazů pokud chceme používat <code class="language-plaintext highlighter-rouge">pacman</code> správce balíků.</p>
<p>Nejdřív musíme vytvořit klíčenku příkazem <code class="language-plaintext highlighter-rouge">pacman-key --init</code>, poté přidáme klíče Arch ARM repozitářů příkazem <code class="language-plaintext highlighter-rouge">pacman-key --populate archlinuxarm</code>. Teď můžete příkazem <code class="language-plaintext highlighter-rouge">pacman -Sy</code> repozitáře synchronizovat.</p>
<p>Jako první balík bychom měli stáhnout <a href="https://wiki.archlinux.org/title/sudo"><code class="language-plaintext highlighter-rouge">sudo</code></a>, abychom nemuseli používat <code class="language-plaintext highlighter-rouge">root</code> uživatele pro všechno nastavování. Nainstalujeme ho příkazem <code class="language-plaintext highlighter-rouge">pacman -S sudo</code>. Dále příkazem <code class="language-plaintext highlighter-rouge">nano /etc/sudoers</code> upravíme konfiguraci. Najdeme následující řádky (<code class="language-plaintext highlighter-rouge">Ctrl+W</code> pro hledání):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>## Uncomment to allow members of group wheel to execute any command
#%wheel ALL=(ALL:ALL) ALL
</code></pre></div></div>
<p>a odstraníme mřížku před <code class="language-plaintext highlighter-rouge">%</code> pro odstranění komentáře. Tím umožníme uživatelům v uživatelské skupině <code class="language-plaintext highlighter-rouge">wheel</code> používat příkaz <code class="language-plaintext highlighter-rouge">sudo</code>.</p>
<p>Nyní přidáme uživatele <code class="language-plaintext highlighter-rouge">alarm</code> do skupiny <code class="language-plaintext highlighter-rouge">wheel</code> příkazem <code class="language-plaintext highlighter-rouge">gpasswd -a alarm wheel</code>. A teď už můžeme používat uživatele <code class="language-plaintext highlighter-rouge">alarm</code> pro různé administrativní operace místo roota.</p>
<h1 id="nastavení-ssh-přístupu">Nastavení SSH přístupu</h1>
<p>Možná vás nebaví zapojovat RPi do monitoru nebo u něj klapat věci do klávesnice v terminálu nebo jen chcete vzdálený přístup. SSH lze povolit skrz OpenSSH, které je na Archu předinstalované. Stačí povolit službu pomocí <code class="language-plaintext highlighter-rouge">systemctl enable sshd</code>. Pro nějakou pokročilou konfiguraci si prohlédněte <a href="https://wiki.archlinux.org/title/OpenSSH#Server_usage">Arch Wiki</a>.</p>
<p>Nyní se stačí připojit skrz nějaký SSH klient na vaše zařízení (pokud neznáte IP, podívejte se skrz příkaz <code class="language-plaintext highlighter-rouge">ip a</code>), třeba skrz <code class="language-plaintext highlighter-rouge">ssh alarm@vase.ip.adresa</code>.</p>
<h1 id="https-problémy">HTTPS problémy</h1>
<p>Pokud máte problémy s SSL nebo komunikací se zabezpečenými servery, zkuste nainstalovat balík <code class="language-plaintext highlighter-rouge">ca-certificates</code> a nastavit systémový čas skrz <code class="language-plaintext highlighter-rouge">timedatectl set-time "2022-10-29 15:00:00</code> (samozřejmě vaše datum).</p>
<h1 id="závěr">Závěr</h1>
<p><img src="/assets/images/rpi-arch/05.png" alt="Arch neofetch"></p>
<p>Instalace je opravdu prostý a snadný proces (i když jsem ho sám dělal asi 5x než mi to nabootovalo), takže určitě zkoušejte a zkoušejte.</p>
</div>
</article>
<div class="post-nav">
<a class="previous" href="/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn.html" title="NordVPN - Jste opravdu v takovém nebezpečí?">NordVPN - Jste opravdu v takovém...</a><span></span>
</div>
<div class="post-related">
<div>Related Articles</div>
<ul>
<li><a class="post-link" href="/programov%C3%A1n%C3%AD/2022/05/22/automatizace.html" title="">Automatizace, automatizace, automatizace</a></li>
<li><a class="post-link" href="/tutori%C3%A1l/2022/10/22/rpi-arch.html" title="">Instalujeme Arch Linux ARM na Raspberry Pi 3</a></li>
<li><a class="post-link" href="/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn.html" title="">NordVPN - Jste opravdu v takovém nebezpečí?</a></li>
<li><a class="post-link" href="/vychyt%C3%A1vky/2022/05/31/codespaces.html" title="">GitHub Codespaces aneb VS Code na VPS</a></li>
</ul>
</div>
<div class="post-comments"> <div id="gitment_thread" class="giscus"></div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/theme-next/theme-next-gitment@1/default.css">
<script src="https://cdn.jsdelivr.net/gh/theme-next/theme-next-gitment@1/gitment.browser.js"></script>
<script src="https://giscus.app/client.js" data-repo="hernikplays/blog" data-repo-id="R_kgDOHr2B6w" data-category="General" data-category-id="DIC_kwDOHr2B684CSIhA" data-mapping="pathname" data-strict="0" data-reactions-enabled="1" data-emit-metadata="0" data-input-position="top" data-theme="transparent_dark" data-lang="en" data-loading="lazy" crossorigin="anonymous" async>
</script>
</div></section>
</div>
</section>
<section class="sidebar" style="margin-left: 15px;">
<!-- Get sidebar items --></section>
</div>
</div>
</main><footer class="site-footer h-card">
<data class="u-url" href="/"></data>
<div class="wrapper">
<div class="site-footer-inner">
<div>Copyright © 2021-2022 hernikplays</div>
<div>Powered by <a title="Jekyll is a simple, blog-aware, static site
generator." href="https://jekyllrb.com/">Jekyll</a> &amp; <a title="Yat, yet
another theme." href="https://github.com/jeffreytse/jekyll-theme-yat">Yat Theme</a>.</div>
<div><a rel="me" href="https://social.linux.pizza/@hernik">Mastodon</a></div>
<div class="footer-col rss-subscribe">Subscribe <a href="/feed.xml">via RSS</a>
</div>
</div>
</div>
</footer>
</body>
</html>

View file

@ -0,0 +1,760 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="google-translate-customization" content="108d9124921d80c3-80e20d618ff053c8-g4f02ec6f3dba68b7-c">
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>GitHub Codespaces aneb VS Code na VPS | Matyáš Caras</title>
<meta name="generator" content="Jekyll v4.3.1">
<meta property="og:title" content="GitHub Codespaces aneb VS Code na VPS">
<meta name="author" content="hernikplays">
<meta property="og:locale" content="en_US">
<meta name="description" content="Nedávno mi přišel e-mail, že jsem byl přidán do beta testování funkce Codespaces na GitHubu. Stručně, Codespaces má být systém ve kterém si vytvoříte vlastní prostředí pro váš repozitář, do kterého si nainstalujete všechny potřebné knihovny, SDK a balíky. Server, na kterém to všechno běží, si platíte u GitHubu a můžete na něj kdekoliv a kdykoliv přejít přes web do webové, narozdíl od výchozího webového VS Code plně vybavené, verzi VS Code nebo nainstalovaný VS Code a upravovat nebo testovat kód.">
<meta property="og:description" content="Nedávno mi přišel e-mail, že jsem byl přidán do beta testování funkce Codespaces na GitHubu. Stručně, Codespaces má být systém ve kterém si vytvoříte vlastní prostředí pro váš repozitář, do kterého si nainstalujete všechny potřebné knihovny, SDK a balíky. Server, na kterém to všechno běží, si platíte u GitHubu a můžete na něj kdekoliv a kdykoliv přejít přes web do webové, narozdíl od výchozího webového VS Code plně vybavené, verzi VS Code nebo nainstalovaný VS Code a upravovat nebo testovat kód.">
<link rel="canonical" href="https://caras.cafe/vychyt%C3%A1vky/2022/05/31/codespaces.html">
<meta property="og:url" content="https://caras.cafe/vychyt%C3%A1vky/2022/05/31/codespaces.html">
<meta property="og:site_name" content="Matyáš Caras">
<meta property="og:type" content="article">
<meta property="article:published_time" content="2022-05-31T00:00:00+00:00">
<meta name="twitter:card" content="summary">
<meta property="twitter:title" content="GitHub Codespaces aneb VS Code na VPS">
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"BlogPosting","author":{"@type":"Person","name":"hernikplays"},"dateModified":"2022-05-31T00:00:00+00:00","datePublished":"2022-05-31T00:00:00+00:00","description":"Nedávno mi přišel e-mail, že jsem byl přidán do beta testování funkce Codespaces na GitHubu. Stručně, Codespaces má být systém ve kterém si vytvoříte vlastní prostředí pro váš repozitář, do kterého si nainstalujete všechny potřebné knihovny, SDK a balíky. Server, na kterém to všechno běží, si platíte u GitHubu a můžete na něj kdekoliv a kdykoliv přejít přes web do webové, narozdíl od výchozího webového VS Code plně vybavené, verzi VS Code nebo nainstalovaný VS Code a upravovat nebo testovat kód.","headline":"GitHub Codespaces aneb VS Code na VPS","mainEntityOfPage":{"@type":"WebPage","@id":"https://caras.cafe/vychyt%C3%A1vky/2022/05/31/codespaces.html"},"url":"https://caras.cafe/vychyt%C3%A1vky/2022/05/31/codespaces.html"}</script>
<!-- End Jekyll SEO tag -->
<link rel="shortcut icon" href="">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/typeface-noto-sans@0.0.72/index.min.css">
<link rel="stylesheet" href="/assets/css/main.css">
<script src="/assets/js/main.js"></script><link type="application/atom+xml" rel="alternate" href="https://caras.cafe/feed.xml" title="Matyáš Caras">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js"></script>
<!-- and it's easy to individually load additional languages -->
<script charset="UTF-8" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/languages/go.min.js"></script>
<script>
// Init highlight js
document.addEventListener('DOMContentLoaded', function(event) {
var els = document.querySelectorAll('pre code')
function addLangData(block) {
var outer = block.parentElement.parentElement.parentElement;
var lang = block.getAttribute('data-lang');
for (var i = 0; i < outer.classList.length; i++) {
var cls = outer.classList[i];
if (cls.startsWith('language-')) {
lang = cls;
break;
}
}
if (!lang) {
cls = block.getAttribute('class');
lang = cls ? cls.replace('hljs ', '') : '';
}
if (lang.startsWith('language-')) {
lang = lang.substr(9);
}
block.setAttribute('class', 'hljs ' + lang);
block.parentNode.setAttribute('data-lang', lang);
}
function addBadge(block) {
var enabled = ('true' || 'true').toLowerCase();
if (enabled == 'true') {
var pre = block.parentElement;
pre.classList.add('badge');
}
}
function handle(block) {
addLangData(block);
addBadge(block)
hljs.highlightBlock(block);
}
for (var i = 0; i < els.length; i++) {
var el = els[i];
handle(el);
}
});
</script>
<style>
/* code language badge */
pre.badge::before {
content: attr(data-lang);
color: #fff;
background-color: #ff4e00;
padding: 0 .5em;
border-radius: 0 2px;
text-transform: uppercase;
text-align: center;
min-width: 32px;
display: inline-block;
position: absolute;
right: 0;
}
/* fix wrong badge display for firefox browser */
code > table pre::before {
display: none;
}
</style>
</head>
<body>
<header class="site-header " role="banner">
<div class="wrapper">
<div class="site-header-inner">
<span class="site-brand"><a class="site-brand-inner" rel="author" href="/">
<img class="site-favicon" title="Matyáš Caras" src="" onerror="this.style.display='none'">
Matyáš Caras
</a>
</span><nav class="site-nav">
<input type="checkbox" id="nav-trigger" class="nav-trigger">
<label for="nav-trigger">
<span class="menu-icon">
<svg viewbox="0 0 18 15" width="18px" height="15px">
<path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"></path>
</svg>
</span>
</label>
<div class="trigger">
<a class="page-link" href="/about.html">ABOUT</a><a class="page-link" href="/archives.html">ARCHIVES</a><a class="page-link" href="/categories.html">CATEGORIES</a><a class="page-link" href="/">HOME</a><a class="page-link" href="/tags.html">TAGS</a>
</div>
</nav>
</div>
</div>
</header>
<script>
function initHeader() {
var lastScrollY = getScrollPos().y;
var documentElement = document.documentElement;
function storeScrollData() {
var y = getScrollPos().y;var scrollStatus = "";
if (y <= 0) {
scrollStatus = "top";
} else if ((window.innerHeight + y) >= document.body.offsetHeight) {
scrollStatus = "bottom";
} else {
var isScrollDown = (y - lastScrollY > 0) ? true : false;
scrollStatus = isScrollDown ? "down" : "up";
}
lastScrollY = y;
documentElement.setAttribute("data-scroll-status", scrollStatus);
}
window.addEventListener('scroll', function(e) {
storeScrollData();
});
storeScrollData();
}
document.addEventListener('DOMContentLoaded', initHeader);
</script>
<script>
function hashLocate(hashValue) {
hashValue = hashValue.replace(/^.*#h-/, '');
hashValue = decodeURIComponent(hashValue);
var element = document.getElementById(hashValue);
if (!element) {
return;
}
var header = document.querySelector('header.site-header');
var headerRect = header.getBoundingClientRect();
var headerTop = Math.floor(headerRect.top);
var headerHeight = Math.floor(headerRect.height);
var scrollPos = getScrollPos();
var offsetY = element.offsetTop - (headerTop + headerHeight + 20);
if (offsetY == scrollPos.y) {
return;
}
if (headerTop == 0 && offsetY > scrollPos.y) {
offsetY += headerHeight + 2;
} else if (headerTop < 0 && offsetY < scrollPos.y) {
offsetY -= headerHeight - 2;
}
smoothScrollTo(offsetY);
}
// The first event occurred
window.addEventListener('load', function(event) {
if (window.location.hash) {
hashLocate(window.location.hash);
}
});
// The first event occurred
window.addEventListener('click', function(event) {
if (event.target.tagName.toLowerCase() == 'a') {
hashLocate(event.target.getAttribute('href'));
}
});
</script>
<div class="theme-toggle">
<input type="checkbox" id="theme-switch">
<label for="theme-switch">
<div class="toggle"></div>
<div class="names">
<p class="light">Light</p>
<p class="dark">Dark</p>
</div>
</label>
</div>
<script>
(function() {
var sw = document.getElementById('theme-switch');
var html = document.getElementsByTagName('html')[0];
var nightModeOption = ('auto' || 'auto').toLowerCase();
var storage = nightModeOption === 'manual'
? localStorage
: sessionStorage;
var themeData = loadThemeData();
function saveThemeData(data) {
storage.setItem('theme', JSON.stringify(data));
}
function loadThemeData() {
var data = storage.getItem('theme');
try {
data = JSON.parse(data ? data : '');
} catch(e) {
data = { nightShift: undefined, autoToggleAt: 0 };
saveThemeData(data);
}
return data;
}
function handleThemeToggle(nightShift) {
themeData.nightShift = nightShift;
saveThemeData(themeData);
html.dataset.theme = nightShift ? 'dark' : 'light';
setTimeout(function() {
sw.checked = nightShift ? true : false;
}, 50);
}
function autoThemeToggle() {
// Next time point of theme toggle
var now = new Date();
var toggleAt = new Date();
var hours = now.getHours();
var nightShift = hours >= 19 || hours <=7;
if (nightShift) {
if (hours > 7) {
toggleAt.setDate(toggleAt.getDate() + 1);
}
toggleAt.setHours(7);
} else {
toggleAt.setHours(19);
}
toggleAt.setMinutes(0);
toggleAt.setSeconds(0);
toggleAt.setMilliseconds(0)
var delay = toggleAt.getTime() - now.getTime();
// auto toggle theme mode
setTimeout(function() {
handleThemeToggle(!nightShift);
}, delay);
return {
nightShift: nightShift,
toggleAt: toggleAt.getTime()
};
}
// Listen the theme toggle event
sw.addEventListener('change', function(event) {
handleThemeToggle(event.target.checked);
});
if (nightModeOption == 'auto') {
var data = autoThemeToggle();
// Toggle theme by local setting
if (data.toggleAt > themeData.autoToggleAt) {
themeData.autoToggleAt = data.toggleAt;
handleThemeToggle(data.nightShift);
} else {
handleThemeToggle(themeData.nightShift);
}
} else if (nightModeOption == 'manual') {
handleThemeToggle(themeData.nightShift);
} else {
var nightShift = themeData.nightShift;
if (nightShift === undefined) {
nightShift = nightModeOption === 'on';
}
handleThemeToggle(nightShift);
}
})();
</script>
<div id="click-to-top" class="click-to-top">
<i class="fa fa-arrow-up"></i>
</div>
<script>
(function () {
const clickToTop = document.getElementById('click-to-top');
window.addEventListener('scroll', () => {
if (window.scrollY > 100) {
clickToTop.classList.add('show')
}else {
clickToTop.classList.remove('show')
}
});
clickToTop.addEventListener('click', () => {
window.smoothScrollTo(0);
});
})();
</script>
<main class="page-content" aria-label="Content">
<div class="wrapper">
<div class="framework">
<section class="main">
<div class="post">
<section>
<header class="post-header">
<h1 class="post-title p-name" itemprop="name headline">GitHub Codespaces aneb VS Code na VPS</h1>
<h2 class="post-subtitle">Dopřejte si trochu luxusu</h2>
<p class="post-meta">
<time class="dt-published" datetime="2022-05-31T00:00:00+00:00" itemprop="datePublished"><i class="fa fa-calendar"></i> May 31, 2022
</time>
<span class="post-reading-time left-vsplit"><i class="fa fa-clock-o"></i> About 2 mins</span>
</p>
<div class="post-tags">
<a class="post-tag" href="/tags.html#github">#github</a><a class="post-tag" href="/tags.html#vps">#vps</a>
</div></header>
<article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">
<div class="post-content e-content" itemprop="articleBody">
<p>Nedávno mi přišel e-mail, že jsem byl přidán do beta testování funkce Codespaces na GitHubu. Stručně, Codespaces má být systém ve kterém si vytvoříte vlastní prostředí pro váš repozitář, do kterého si nainstalujete všechny potřebné knihovny, SDK a balíky. Server, na kterém to všechno běží, si platíte u GitHubu a můžete na něj kdekoliv a kdykoliv přejít přes web do webové, narozdíl od výchozího webového VS Code plně vybavené, verzi VS Code nebo nainstalovaný VS Code a upravovat nebo testovat kód.</p>
<p>Hodí se pro lidi, kteří nechtějí tahat např. do školy nebo do práce, kde nesmí instalovat externí aplikace, svůj vlastní notebook.
Parametry</p>
<p>V betě je možné testovat pouze výchozí možnost 4 jádra + 8GB RAM + 32GB úložiště, což definitivně stačí pro osobní a malé projekty. Do konce bety neplatíte nic, ale 4 jádra vyjdou na $0.36 (asi 8,3 kč) za hodinu, tj za hodinu aktivního používání. Codespace se vám automaticky vypne, pokud není po stanovenou dobu nepoužíván, takže můžete předejít placení katastrofických částek.
<img src="/assets/images/codespaces/1.jpg" alt="Ceny Codespaces"></p>
<p>Je to určitě výhodnější, než si platit např. hotové VPS, pokud ho tedy nepoužíváte i na něco smysluplnějšího.
Moje zkušenost</p>
<p>Samozřejmě jsem nemohl odolat a na OpenCanteen jsem si jeden nechal vytvořit, aniž bych věděl do čeho se vrhám.</p>
<p>Codespace se vytváří jednoduše kliknutím na tlačítko “Code” ve vašem repozitáří, kde se vám nově zobrazí možnost si Codespace vytvořit.</p>
<p>Ve výchozím stavu běží server na Ubuntu. Pokud nenajdete docker obraz nebo devcontainer konfigurační soubor, musíte si samozřejmě vše nainstalovat sami, což zas tolik nevadí, protože to nejspíš budete dělat jen jednou, pokud si nebudete s obrazem stroje nějak zahrávat.</p>
<p>Instalace všeho však probíhá svižně, jelikož asi v Microsoftu mají na rychlejší internet, než já. Samozřejmě vše musíte instalovat skrze terminál (což mě celkem ranilo, jelikož instalovat Android SDK pro flutter byla celkem fuška).</p>
<p>Pokud používáte Settings Sync ve VS Code, automaticky se vám synchronizují nastavení a rozšíření. Pro pokročilé upravení prostředí slouží konfigurační soubor devcontainer.json
<img src="/assets/images/codespaces/2.jpg" alt="Ceny Codespaces"></p>
<p>Jakmile máte všechno nastavené, už stačí jen využít starého známého Visual Studio Code, které funguje úplně stejně jako na lokálním zařízení. Na Codespace se můžete kdykoli připojit přes webovou adresu.</p>
<p>Za mě velice praktické pro dříve uvedené typy lidí, už jen záleží, jestli se to zrovna vám za ty peníze vyplatí. Dokumentace je možná trochu chaotická, alespoň pro uživatele co se nevyznají v technologiích jako kontejnery či docker a většiny funkcí využije jen skutečný poweruser (což já určitě nejsem).</p>
</div>
</article>
<div class="post-nav">
<a class="previous" href="/programov%C3%A1n%C3%AD/2022/05/22/automatizace.html" title="Automatizace, automatizace, automatizace">Automatizace, automatizace, automatizace</a><a class="next" href="/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn.html" title="NordVPN - Jste opravdu v takovém nebezpečí?">NordVPN - Jste opravdu v takovém...</a>
</div>
<div class="post-related">
<div>Related Articles</div>
<ul>
<li><a class="post-link" href="/vychyt%C3%A1vky/2022/05/31/codespaces.html" title="NordVPN - Jste opravdu v takovém nebezpečí?">GitHub Codespaces aneb VS Code na VPS</a></li>
<li><a class="post-link" href="/bezpe%C4%8D%C3%AD/2022/07/19/nordvpn.html" title="NordVPN - Jste opravdu v takovém nebezpečí?">NordVPN - Jste opravdu v takovém nebezpečí?</a></li>
<li><a class="post-link" href="/programov%C3%A1n%C3%AD/2022/05/22/automatizace.html" title="NordVPN - Jste opravdu v takovém nebezpečí?">Automatizace, automatizace, automatizace</a></li>
<li><a class="post-link" href="/tutori%C3%A1l/2022/10/22/rpi-arch.html" title="NordVPN - Jste opravdu v takovém nebezpečí?">Instalujeme Arch Linux ARM na Raspberry Pi 3</a></li>
</ul>
</div>
<div class="post-comments"> <div id="gitment_thread" class="giscus"></div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/theme-next/theme-next-gitment@1/default.css">
<script src="https://cdn.jsdelivr.net/gh/theme-next/theme-next-gitment@1/gitment.browser.js"></script>
<script src="https://giscus.app/client.js" data-repo="hernikplays/blog" data-repo-id="R_kgDOHr2B6w" data-category="General" data-category-id="DIC_kwDOHr2B684CSIhA" data-mapping="pathname" data-strict="0" data-reactions-enabled="1" data-emit-metadata="0" data-input-position="top" data-theme="transparent_dark" data-lang="en" data-loading="lazy" crossorigin="anonymous" async>
</script>
</div></section>
</div>
</section>
<section class="sidebar" style="margin-left: 15px;">
<!-- Get sidebar items --></section>
</div>
</div>
</main><footer class="site-footer h-card">
<data class="u-url" href="/"></data>
<div class="wrapper">
<div class="site-footer-inner">
<div>Copyright © 2021-2022 hernikplays</div>
<div>Powered by <a title="Jekyll is a simple, blog-aware, static site
generator." href="https://jekyllrb.com/">Jekyll</a> &amp; <a title="Yat, yet
another theme." href="https://github.com/jeffreytse/jekyll-theme-yat">Yat Theme</a>.</div>
<div><a rel="me" href="https://social.linux.pizza/@hernik">Mastodon</a></div>
<div class="footer-col rss-subscribe">Subscribe <a href="/feed.xml">via RSS</a>
</div>
</div>
</div>
</footer>
</body>
</html>