<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Borys Turchyk Personal Blog</title>
    <subtitle>A collection of news, thoughts and ideas I&#39;d like to share with the world - not that I expect the world to care, but some of it could be useful for someone. Another goal that the blog serves is sharing the updates for whatever projects I&#39;m working on.</subtitle>
    <link href="https://hydralien.net/blog/feed.xml" rel="self"/>
    <link href="https://hydralien.net/blog/"/>
    <updated>2025-12-29T00:00:00Z</updated>
    <id>https://hydralien.net/blog/</id>
    <author>
        <name>Borys Turchyk</name>
        <email>hydralien@gmail.com</email>
    </author>
    
    <entry>
        <title>All Hail The New Blog!</title>
        <link href="https://hydralien.net/blog//posts/blog-is-back/"/>
        <updated>2021-06-05T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/blog-is-back/</id>
        <content type="html">&lt;p&gt;I used to have a WordPress blog hosted on DreamHost, but since I moved my website out to Netlify (for totally mercantile reasons,
as DreamHost hiked the price, and so I thought that was unreasonable money for my humble little page),
I decided that keeping the blog the way it is made no sense - and I reckoned there&#39;s no value in converting
existing articles to a new platform (as those pages were mostly of sentimental value to me),
so I decided to just start anew.&lt;/p&gt;
&lt;p&gt;This new attempt is mostly about product updates and personal development details, and perhaps also some random thoughts on IT world, book reviews and other random things.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Introducing Pidging: A Travel Communication Helper App</title>
        <link href="https://hydralien.net/blog//posts/pidging-intro/"/>
        <updated>2021-06-06T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/pidging-intro/</id>
        <content type="html">&lt;h4&gt;The problem&lt;/h4&gt;
&lt;p&gt;Have you ever been in a situation when you walk into a small grocery store in a foreign country, you want to buy some local produce, but you can&#39;t say a word the shop owner would understand - because they don&#39;t speak any of the languages you do, and you don&#39;t speak any languages they do?&lt;/p&gt;
&lt;p&gt;You have probably ended up pointing to things saying &amp;quot;this&amp;quot; and &amp;quot;that&amp;quot; in English, and showing your fingers indicating quantity, and you got away with some of the things you wanted - but if you&#39;re anything like me, you might&#39;ve retreated without buying half of the thing you&#39;d like (or getting something else entirely) and feeling frustrated with yourself for not being able to communicate.&lt;/p&gt;
&lt;h4&gt;In comes the Pidging!&lt;/h4&gt;
&lt;p&gt;So is it possible to have more fulfilling experience with journey communications? Well, certainly, you could study the language, understand grammar, proper pronunciation, build up vocabulary and start speaking it - but for most of us, that&#39;s not a feasible solution for a one-week trip to a foreign country.&lt;/p&gt;
&lt;p&gt;Pidging is aiming to help in another fashion, by providing a vocabulary of simple words and phrases you could use in any situation, and a rapid translation to over 90 languages with an ability to store selected translations offline. Sure, you won&#39;t be able to maintain an elaborate conversation, or even build a grammatically correct sentence, but you&#39;d certainly help people understand what you want exactly (and not get champagne instead of coffee in the morning; unless that&#39;s a desirable effect), ask for directions, read signs and so on - and also (at least partially) understand what people are saying back to you.&lt;/p&gt;
&lt;p&gt;The provided vocabulary is by no means complete, because everyone considers different words and phrases more important than others, so Pidging also offers an ability to add your own word/phrase collections and translate them in new languages automatically!&lt;/p&gt;
&lt;h4&gt;Where to get&lt;/h4&gt;
&lt;p&gt;If that sounds helpful, give it a try - the app is free and available for both iOS and Android. Download links are on its web page: &lt;a href=&quot;https://hydralien.net/pidging/&quot;&gt;https://hydralien.net/pidging/&lt;/a&gt;&lt;/p&gt;
&lt;h5&gt;Bon voyage!&lt;/h5&gt;
</content>
    </entry>
    
    <entry>
        <title>Moving the blog to Eleventy</title>
        <link href="https://hydralien.net/blog//posts/eleventy-test/"/>
        <updated>2021-07-08T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/eleventy-test/</id>
        <content type="html">&lt;h3&gt;It finally happened!&lt;/h3&gt;
&lt;p&gt;For a long while, I was thinking of moving the blog to some static page generator,
so I would preferably write pages in Markdown or some other simple formatting.&lt;/p&gt;
&lt;p&gt;But since the rest of my website is in Vue and I quite like it that way as I&#39;d rather have more flexibility
when adding more projects to it, I first decided to just move away from Wordpress and write pages in raw HTML.&lt;/p&gt;
&lt;p&gt;Because why not.&lt;/p&gt;
&lt;p&gt;But since I had some time today and wanted to dig into something new, I moved the blog to &lt;a href=&quot;https://www.11ty.dev/&quot;&gt;Eleventy&lt;/a&gt;.
Well, I first tried to plug in some Markdown plugins for Vue so I cou;d maybe just write Vue components in Markdown,
but that didn&#39;t work - so I decided to dedicate some efforts to get me some Eleventy experience.&lt;/p&gt;
&lt;p&gt;It also neatly builds as a single project (Vue and 11ty) on Netlify, so I&#39;m glad.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Traject - New Project In The Making</title>
        <link href="https://hydralien.net/blog//posts/traject-intro/"/>
        <updated>2021-11-06T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/traject-intro/</id>
        <content type="html">&lt;h3&gt;Idea&lt;/h3&gt;
&lt;p&gt;Traject is an adventure planner, route marketplace and safety notifier.&lt;/p&gt;
&lt;h3&gt;Vision&lt;/h3&gt;
&lt;p&gt;We are aiming to make outdoor activities safer and less worrisome by sharing plans with friends and family, return/overdue notifications, offline route info storage, and a place to get and share route information.&lt;/p&gt;
&lt;h3&gt;Problem&lt;/h3&gt;
&lt;p&gt;Outdoors are awesome but also dangerous, and when nobody knows where you’re going and when you’re expected to be back it’s equally worrying for both you and people close to you. Precise and detailed route information also greatly helps potential rescue efforts. Additionally, having all the details with you makes you more informed and helps making better decisions.&lt;/p&gt;
&lt;h3&gt;Pitch&lt;/h3&gt;
&lt;p&gt;Traject is an adventure planner, route marketplace and safety notifier. We are developing a platform (web and mobile apps) to help outdoors adventurers stay safe, track and share their achievements with return/overdue notifications to selected contacts, sharing location and route status/results, storing offline route plan and a marketplace to get reliable route details.&lt;/p&gt;
&lt;h3&gt;Reason&lt;/h3&gt;
&lt;p&gt;I&#39;m a passionate adventurer (climber, hiker, cyclist, runner and alpinist) and have first-hand interest in the project as its future customer, as first of all I want to make my own adventures safer, more reliable and informed. I&#39;ve been using a set of odd tools such as calendar, Google Docs, written and verbal notes, paper books and so on, and I&#39;d like to have a tool to have it all at my fingertips.&lt;/p&gt;
&lt;h3&gt;Competition&lt;/h3&gt;
&lt;p&gt;Cairn and MountainHiking Project - first requires paid subscription and provides very limited route details, second has good free route information but no notification. We&#39;re going to do both plus tracking and sharing for free, plus a marketplace.&lt;/p&gt;
&lt;h3&gt;Current state&lt;/h3&gt;
&lt;p&gt;The project is live in a form of a landing page at &lt;a href=&quot;https://traject.online/&quot;&gt;https://traject.online/&lt;/a&gt;, but I&#39;m hoping to get some funds to build it into a real thing - or get some time to do it myself, at least to a somewhat usable point.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Perpetually Drunk Mondrian, An Art Project</title>
        <link href="https://hydralien.net/blog//posts/drunk-mondrian/"/>
        <updated>2021-11-08T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/drunk-mondrian/</id>
        <content type="html">&lt;h3&gt;Art Driven Development&lt;/h3&gt;
&lt;p&gt;A pure fun art project I&#39;ve been thinking about for quite a long time and finally got some time to make: &lt;a href=&quot;https://hydralien.github.io/drunk-mondrian/&quot;&gt;https://hydralien.github.io/drunk-mondrian/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The original idea was just randomly moving the pen on paper without thinking about it (preferably thinking about something completely different) and then filling some random parts with equally random colors.
I originally wanted to use real pen, paper and watercolor but then thought of &lt;a href=&quot;https://www.threadless.com/shop/@threadless/design/drunk-mondrian/mens/shoes&quot;&gt;one of my favourite fabric prints&lt;/a&gt; and decided to make it a development exercise.&lt;/p&gt;
&lt;p&gt;It&#39;s essentially a bunch of randomization stringed together in a fairly inefficient manner, but it works and I kinda like the results:&lt;/p&gt;
&lt;img src=&quot;https://github.com/hydralien/drunk-mondrian/raw/main/img/screenshot_2.png&quot; alt=&quot;How Results Look&quot; style=&quot;width: 100%;&quot; /&gt;
&lt;p&gt;The code is open and could be found here: &lt;a href=&quot;https://github.com/hydralien/drunk-mondrian&quot;&gt;https://github.com/hydralien/drunk-mondrian&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Yet Another Interview Rant, Or My Thoughts On The Process</title>
        <link href="https://hydralien.net/blog//posts/yet-another-interview-rant/"/>
        <updated>2021-11-22T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/yet-another-interview-rant/</id>
        <content type="html">&lt;h4&gt;Who needs another rant?&lt;/h4&gt;
&lt;p&gt;This is really a set of notes and key consideration points for myself, and I&#39;ll grow and expand it as I go through the interviewing process.&lt;/p&gt;
&lt;p&gt;As someone that hasn&#39;t attended interviews (especially from the candidate side) for a long while, getting back into the process
produces surprisingly a lot of unexpected negative experience and reveals a number of inefficient practices, which I want to list here along with what I think works better.&lt;/p&gt;
&lt;p&gt;There&#39;s no shortage of talks and ideas about how to improve the interview process. One of the most useful thoughts,
that &lt;em&gt;interview performance does not equal job performance&lt;/em&gt;, was recently covered here:
&lt;a href=&quot;https://blog.professorbeekums.com/2021/interview-performance/&quot;&gt;https://blog.professorbeekums.com/2021/interview-performance/&lt;/a&gt; - and even though I have my reservations about some parts of it
(like 2-hour interviews), its overall message is really thoughtful.&lt;/p&gt;
&lt;h4&gt;Things to consider (from the candidate side)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Ask to thoroughly elaborate on the interview process to understand all steps.&lt;/li&gt;
&lt;li&gt;Beware of tasks that take &amp;quot;whatever you think is enough&amp;quot; time or over 4 hours: large scope and lots of work.&lt;/li&gt;
&lt;li&gt;Ask if the assignment requires specific stack or any other prior knowledge.&lt;/li&gt;
&lt;li&gt;If the interview looks or feels surprising or not going well, speak up and potentially stop early: the outcome is unlikely to be positive so it&#39;s a waste of time.&lt;/li&gt;
&lt;li&gt;Unless you&#39;re early in the interviewing process or haven&#39;t done it in a while - then failing is also important as it gives you knowledge and experience for next attempts.&lt;/li&gt;
&lt;li&gt;If the interview is long, ask to break down. If they&#39;re back-to-back, ask to schedule on different days.&lt;/li&gt;
&lt;li&gt;If possible, ask to give you feedback after each interview so if one step is blown the others could be avoided. Unless the goal of interviewing is learning.&lt;/li&gt;
&lt;li&gt;Do not close up to the questions you don&#39;t like; asking clarifying questions or reasons behind the question might help to relax and form a better answer.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Red flags&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Separate coding and/or system design interviews after elaborate take-home assignment (not related to the assignment).&lt;/li&gt;
&lt;li&gt;More-than-one-hour interviews should be split or break provided.&lt;/li&gt;
&lt;li&gt;Time-constrained coding in front of something is stressful and restricted.&lt;/li&gt;
&lt;li&gt;Several coding interviews instead of one or take-home task.&lt;/li&gt;
&lt;li&gt;Take-home assignment subject/goals are unrelated to company business.&lt;/li&gt;
&lt;li&gt;Any IQ-kind-of-test (called &amp;quot;aptitude test&amp;quot; nowadays) is a huge no-no, as it&#39;s a repetitive blunder that doesn&#39;t really assess any personal qualities.&lt;/li&gt;
&lt;li&gt;Tests or forms to fill without prior personal communication or clear explanation of hiring process.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Process pitfalls&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Live coding interview of any kind is stressful and many people don&#39;t perform well. If questions is purely algorithmic or  irrelevant to the company it&#39;s also frustrating.&lt;/li&gt;
&lt;li&gt;Take-home assignment without follow-up.&lt;/li&gt;
&lt;li&gt;Looking for an all-round ready-made candidate without considering that engineers learn and adapt quickly.&lt;/li&gt;
&lt;li&gt;Requiring by-the-book knowledge of development and design patterns.&lt;/li&gt;
&lt;li&gt;Very specific system design question with expectations of follow-up questions - questions implying more information or discussion should be open and vague.&lt;/li&gt;
&lt;li&gt;Making engineers do HR&#39;s job by asking behavioral questions for the sake of it (often just reading them).&lt;/li&gt;
&lt;li&gt;Asking the candidate to describe their solution while coding or talking to them while they code (breaks focus).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Better options&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Meaningful take-home assignment that are relevant to what team/company does.&lt;/li&gt;
&lt;li&gt;If the team is fixed on live coding, at least coding problems could be relevant to the company domain.&lt;/li&gt;
&lt;li&gt;Technical interview is a review of the assignment plus touching on follow-up subjects like performance, scaling, monitoring, security and so on&lt;/li&gt;
&lt;li&gt;Merge request review with comments as it resembles real life.&lt;/li&gt;
&lt;li&gt;Breaking assignment into several small tasks building on each other or exploring different areas.&lt;/li&gt;
&lt;li&gt;Presenting the candidate with established project and infrastructure to build on, or clearly mention infrastructure is the (potential) part of the assignment.&lt;/li&gt;
&lt;li&gt;Provide excessive set of problems to solve in flex-limited time (&amp;quot;no more than 3-4 hours&amp;quot;), clearly mentioning that solving all is not required, just as many as candidate feels reasonable within given time.&lt;/li&gt;
&lt;li&gt;Another option: let candidate prioritize which problems to solve, mentioning that that&#39;s the part of the assignment (so solving all is inherently not the goal)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Little Book Of Calm&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;People usually mean well - they want to hire ideal candidates, people who know the most, who could start contributing right away.
And it&#39;s their right and choice - so as long as I&#39;d wish interviewers would consider that candidate could learn whatever is missing or perform better in non-time-constrained environment, I understand the other side as well. It&#39;s OK.&lt;/li&gt;
&lt;li&gt;The interview is a lengthy process - collecting feedback takes time, people are busy, things get forgotten and abandoned for no ill reason. Things happen, and it&#39;s OK.&lt;/li&gt;
&lt;li&gt;I will fail to pass interviews, I will pass but still considered not a good fit, my application will not be considered, another candidate will get hired before me,
some outcomes will not satisfy me and I&#39;ll bail, and many other things will get in the way. That&#39;s OK, everyone will find the right place/candidate in the end.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Follow-up&lt;/h4&gt;
&lt;p&gt;This page is to be updated with more thoughts, findings and ideas.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Key Points Of A Philosophy Of Software Design</title>
        <link href="https://hydralien.net/blog//posts/philosophy-of-software-design/"/>
        <updated>2021-11-23T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/philosophy-of-software-design/</id>
        <content type="html">&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&amp;quot;It&#39;s a great feeling to discover a solution that is both simple and powerful. A clean, simple and obvious design is a beautiful thing&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;What Philosophy?&lt;/h4&gt;
&lt;img src=&quot;https://i.gr-assets.com/images/S/compressed.photo.goodreads.com/books/1531857377l/39996759._SX318_.jpg&quot; alt=&quot;A Philosophy Of Software Design book cover&quot; style=&quot;max-width: 30%;&quot; /&gt;
&lt;p&gt;This is about the book &amp;quot;&lt;a href=&quot;https://www.goodreads.com/book/show/39996759-a-philosophy-of-software-design&quot;&gt;A Philosophy Of Software Design&lt;/a&gt;&amp;quot; by &lt;a href=&quot;https://en.wikipedia.org/wiki/John_Ousterhout&quot;&gt;John Ousterhout&lt;/a&gt; that I read at some point
and wanted to save some key thoughts in a succinct and structured way. I found the principles described in the book really thoughtful and
applicable to the real life - and even though I have some reservations about certain points, the difference of opinions does
not make this book any less useful or relevant (perhaps the opposite, even more so).&lt;/p&gt;
&lt;h4&gt;Key thoughts (in no particular order)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Make deeper modules, hiding technical details inside and exposing simple interface with minimal required functionality. Also use many defaults so only required values would be provided.&lt;/li&gt;
&lt;li&gt;Do not use order of operations as a principle for module structure, instead focus on what pieces are required to perform an operation and put them together.&lt;/li&gt;
&lt;li&gt;Generalise - the less specific method user needs to remember the better. If method is designed for just one case, maybe or can be merged with another similar  functionality?&lt;/li&gt;
&lt;li&gt;Do not over generalise - trying to build a very generic interface leads to more cognitive load, more complexity and harder to maintain/easier to break systems.&lt;/li&gt;
&lt;li&gt;No simple pass through method, they indicate that something is wrong with abstraction.&lt;/li&gt;
&lt;li&gt;&amp;quot;Most modules have more users than developers, so it&#39;s better for the developed to suffer thant the users&amp;quot; :)&lt;/li&gt;
&lt;li&gt;It&#39;s more important to have a simple interface than a simple implementation.&lt;/li&gt;
&lt;li&gt;&amp;quot;Pull complexity downwards&amp;quot; - meaning to the lower implementation level, where fewer people would need to deal with it.&lt;/li&gt;
&lt;li&gt;Don&#39;t overdo things, keep abstractions native to a specific area at that very level only.&lt;/li&gt;
&lt;li&gt;&amp;quot;Define errors out of existence&amp;quot;, as error handling causes unnecessary complicated code, and &amp;quot;overall, the best way to reduce bugs is to make software simpler&amp;quot;. Just die if it&#39;s bad, if it&#39;s important enough. (&lt;strong&gt;IMO&lt;/strong&gt; the best way is to throw typed exceptions and catch them at higher level where they could be converted in interface/user-visible errors).&lt;/li&gt;
&lt;li&gt;Design it twice - outline pros and cons of the first approach, check how it would work in a few month/year and see if you can come up with something better. &amp;quot;Eventually, everyone reaches a point where your first ideas are not good enough&amp;quot;; also, &amp;quot;it isn&#39;t that you aren&#39;t smart; it&#39;s that the problems are really hard!&amp;quot;.&lt;/li&gt;
&lt;li&gt;&amp;quot;The process of writing comments, if done correctly, will actually improve a system&#39;s design&amp;quot;. Also, &amp;quot;inadequate documentation creates a huge and unnecessary drag on software development&amp;quot; and &amp;quot;if I must read the code of a method on order to use it, there is no abstraction&amp;quot;. Inline comments should describe things that are not immediately clear from the code and not repeat the code itself.&lt;/li&gt;
&lt;li&gt;If finding a simple yet descriptive and clear name for a thing is hard then maybe the design of the thing itself is not clear.&lt;/li&gt;
&lt;li&gt;Names should be clear, common, consistent and same name should server same purpose.&lt;/li&gt;
&lt;li&gt;Readability should be determined by readers, not writers.&lt;/li&gt;
&lt;li&gt;Delaying the documentation (commenting the code) often means it will never be written.&lt;/li&gt;
&lt;li&gt;&amp;quot;If you are not making [software] design better, you&#39;re probably making it worse&amp;quot;.&lt;/li&gt;
&lt;li&gt;Don&#39;t change existing connections (unless you&#39;re changing everything) - keeping consistency is better than better style in some places but not all.&lt;/li&gt;
&lt;li&gt;TDD usually divides attention on specific features rather then design; when tests-first approach makes sense is fixing issues: you replicate it with failing test, then fix it.&lt;/li&gt;
&lt;li&gt;&amp;quot;Measure before modifying&amp;quot; - mostly about performance here, but a good principle on general for any changes or improvements.&lt;/li&gt;
&lt;li&gt;&amp;quot;It&#39;s a great feeling to discover a solution that is both simple and powerful. A clean, simple and obvious design is a beautiful thing&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Summary&lt;/h4&gt;
&lt;p&gt;It&#39;s a great book - clear, concise, very relevant and applicable, and of very palatable size. Great read for anyone related to a software systems design.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Stopping Python socketserver.ThreadingTCPServer On Keyboard Interrupt</title>
        <link href="https://hydralien.net/blog//posts/python-threading-tcp-server-shutdown/"/>
        <updated>2021-12-02T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/python-threading-tcp-server-shutdown/</id>
        <content type="html">&lt;h4&gt;socketserver.ThreadingTCPServer&lt;/h4&gt;
&lt;p&gt;Curiously enough, Python documentation suggests writing async TCP server using mixins (see &lt;a href=&quot;https://docs.python.org/3/library/socketserver.html#socketserver.ThreadingMixIn&quot;&gt;https://docs.python.org/3/library/socketserver.html#socketserver.ThreadingMixIn&lt;/a&gt;)
while there&#39;s existing class that does it already hence not requiring boilerplate code - ant it&#39;s socketserver.ThreadingTCPServer.&lt;/p&gt;
&lt;p&gt;Its usage is pretty much like socketserver.TCPServer in the documentation - here&#39;s an echo-like server example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class TCPServerHandler(socketserver.StreamRequestHandler):
    def handle(self):
        data_line: str = &amp;quot;_&amp;quot;
        data_processor = DataProcess()
        while data_line:
            data_line = self.rfile.readline().strip().decode(&#39;ascii&#39;)
            if data_line == &#39;.&#39;:
                print(&amp;quot;Connection terminated by client request&amp;quot;)
                self.finish()
                return
            self.request.sendall(data_line)

with socketserver.ThreadingTCPServer((&amp;quot;localhost&amp;quot;, 5000), TCPServerHandler) as server:
    try:
        server.daemon_threads = True
        server.serve_forever()
    except (KeyboardInterrupt, SystemExit):
        log.error(&amp;quot;Shutdown signal received&amp;quot;)
    finally:
        print(&#39;Stopping server&#39;)
        server.server_close()
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Stopping the server&lt;/h4&gt;
&lt;p&gt;And it&#39;s all nice and fine, with one exception - the using code from the documentation doesn&#39;t stop on the keyboard
interrupt. Which is annoying as the search for the problem brings many (valid) discussions on how the keyboard events are
relevant to the main thread only so the server isn&#39;t responsible for it, but there was no valid solution - setting the
recommended &lt;em&gt;server.daemon = True&lt;/em&gt; flag did nothing.&lt;/p&gt;
&lt;p&gt;The solution was surprisingly simple and intuitive, but not really described anywhere - to use the &lt;strong&gt;&lt;em&gt;server.daemon_threads = True&lt;/em&gt;&lt;/strong&gt; flag instead! Oh well...&lt;/p&gt;
&lt;p&gt;I&#39;ll leave it here in case it pops up in someone&#39;s search and helps with the problem.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Hitting The Books: Short Review Of The &quot;Building Microservices&quot; Book</title>
        <link href="https://hydralien.net/blog//posts/building-microservices-book-review/"/>
        <updated>2021-12-15T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/building-microservices-book-review/</id>
        <content type="html">&lt;h3&gt;What Book?&lt;/h3&gt;
&lt;img src=&quot;https://samnewman.io/books/img/building%20microservices_2ed_comp.png&quot; alt=&quot;Building Microservices book cover&quot; style=&quot;width: 30%;&quot; /&gt;
&lt;p&gt;One of the recent curiosity-induced reads I went through (significantly influenced by outcomes of the job search and the
current IT development market conditions) is the &amp;quot;&lt;a href=&quot;https://samnewman.io/books/building_microservices_2nd_edition/&quot;&gt;Building Microservices&lt;/a&gt;&amp;quot; book by &lt;a href=&quot;https://samnewman.io/&quot;&gt;Sam Newman&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;General Impression&lt;/h3&gt;
&lt;p&gt;I was at first concerned with the size - it&#39;s almost 600 pages (586 to be precise), and large books usually mean lots of
too specific details (think code listings) or too diluted information (think lots of stories and repetition of ideas).
But it was highly recommended, so I decided to give it a try (although it&#39;s not the cheapest book either).&lt;/p&gt;
&lt;p&gt;And I have to say I don&#39;t regret my decision - even though the book is titled &amp;quot;Building Microservices&amp;quot;, it&#39;s actually about
building distributed systems in general. Or even broader, it&#39;s about making decisions for the system design: monolithic
architectures are mentioned in the book almost as often as service-oriented ones, and it&#39;s emphasised repeatedly that
the reader might not need to consider neither SOA in general nor microservices in particular, as solid monolith might work
just fine (for instance, if the project in a startup with rapidly changing directions, uncertain future and a small team where
everyone works on everything).&lt;/p&gt;
&lt;p&gt;So in the end the size of the book was well justified as it covers a variety of subjects - storage, deployment, monitoring,
scaling, UI decomposition, team scope and responsibilities and so on and so forth.
And it also does in a fairly succinct yet clear fashion, which makes it really easy to understand and inject the information.
Additionally, it has a lot of references to other useful materials with more specifics on each subject.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;It&#39;s still a lot of information, and in some parts it&#39;s still too specific and detailed, while in the others it&#39;s vague and imprecise.
Not everything will stick and be easy to recall after time, and not every chapter has a clear action points to extract.
But it&#39;s a good reference to come back to when needed, and I feel like I&#39;ve learned a lot from this book - even when it
describes the already known techniques and aspects, it still does that in a way I wouldn&#39;t be able to do myself.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>TIL: Less Known Semantic Elements In HTML</title>
        <link href="https://hydralien.net/blog//posts/til-html-less-used-semantic-elements/"/>
        <updated>2021-12-15T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/til-html-less-used-semantic-elements/</id>
        <content type="html">&lt;h3&gt;Semantic Formatting&lt;/h3&gt;
&lt;p&gt;Recent episode &lt;a href=&quot;https://podcast.smashingmagazine.com/episodes/is-the-web-dead-with-chris-ferdinandi&quot;&gt;&amp;quot;Is The Web Dead?&amp;quot; of Smashing Podcast&lt;/a&gt;
(it&#39;s a very good discussion BTW) highlighted some things in modern HTML markup I was unaware of. I can&#39;t really position
myself as any sort of frontend specialist, although I&#39;ve been creating web pages of various complexity for as far as
my IT career goes, so any extra knowledge around it is still highly relevant.&lt;/p&gt;
&lt;p&gt;The podcast touched specifically on details/summary elements, however that got me thinking there must be more, and there definitely is.
This list is based on a portion of &lt;a href=&quot;https://www.w3schools.com/html/html5_semantic_elements.asp&quot;&gt;W3Schools article&lt;/a&gt;, plus some extra s I also missed.&lt;/p&gt;
&lt;h3&gt;The Elements&lt;/h3&gt;
&lt;p&gt;From that same article,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&amp;quot;Semantic elements = elements with a meaning.&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;which means a lot of HTML elements fall under this category - &lt;em&gt;form&lt;/em&gt;, &lt;em&gt;article&lt;/em&gt;, &lt;em&gt;header&lt;/em&gt; and so on. Those are better know though,
so here I&#39;m listing several examples of lesser known elements in the category, namely:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;details / summary&lt;/li&gt;
&lt;li&gt;figure / figcaption&lt;/li&gt;
&lt;li&gt;dl / dt / dd (although I guess these are a tad bit less semantic)&lt;/li&gt;
&lt;li&gt;time&lt;/li&gt;
&lt;li&gt;mark&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And so,&lt;/p&gt;
&lt;h4&gt;Details / Summary&lt;/h4&gt;
&lt;details style=&quot;border: 1px solid; padding: 0.3em; border-radius: 5px;&quot;&gt;
    &lt;summary&gt;Specifics of the element&lt;/summary&gt;
    Specify details that the user can open and close on demand. Closed by default, and can nest any sort of content.  
&lt;/details&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;details style=&amp;quot;border: 1px solid; padding: 0.3em; border-radius: 5px;&amp;quot;&amp;gt;
    &amp;lt;summary&amp;gt;Specifics of the element&amp;lt;/summary&amp;gt;
    Specify details that the user can open and close on demand. Closed by default, and can nest any sort of content.  
&amp;lt;/details&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Figure / Figcaption&lt;/h4&gt;
&lt;figure&gt;
Specifies the self-contained content (images, illustrations, code) along with the caption:
&lt;pre&gt;&lt;code&gt;&amp;lt;figure&amp;gt;
    Specifies the self-contained content (images, illustrations, code) along with the caption
    &amp;lt;figcaption&amp;gt;
        Figure/figcaption code example
    &amp;lt;/figcaption&amp;gt;
&amp;lt;figure&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;figcaption&gt;
    Figure/figcaption code example
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h4&gt;Description List / Description Term / Description Details&lt;/h4&gt;
&lt;p&gt;Or dl / dt / dd. Typical usage to implement a list of terms with description (e.g. glossary). An example:&lt;/p&gt;
&lt;dl&gt;
    &lt;dt&gt;
        dl: a description list.
        &lt;/dt&gt;&lt;dd&gt;
            The element encloses a list of groups of terms and descriptions.
        &lt;/dd&gt;
    
    &lt;dt&gt;
        dt: a term in a description or definition list.
        &lt;/dt&gt;&lt;dd&gt;
            Must be used inside a dl element.
        &lt;/dd&gt;
    
    &lt;dt&gt;
        dd: description details.
        &lt;/dt&gt;&lt;dd&gt;
            Provides the description, definition, or value for the preceding term.
        &lt;/dd&gt;
    
&lt;/dl&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;dl&amp;gt;
    &amp;lt;dt&amp;gt;
        dl: a description list.
        &amp;lt;dd&amp;gt;
            The element encloses a list of groups of terms and descriptions.
        &amp;lt;/dd&amp;gt;
    &amp;lt;/dt&amp;gt;
    &amp;lt;dt&amp;gt;
        dt: a term in a description or definition list.
        &amp;lt;dd&amp;gt;
            Must be used inside a &amp;lt;dl&amp;gt; element.
        &amp;lt;/dd&amp;gt;
    &amp;lt;/dt&amp;gt;
    &amp;lt;dt&amp;gt;
        dd: description details.
        &amp;lt;dd&amp;gt;
            Provides the description, definition, or value for the preceding term.
        &amp;lt;/dd&amp;gt;
    &amp;lt;/dt&amp;gt;
&amp;lt;/dl&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Time&lt;/h4&gt;
&lt;p&gt;Used for a formatting of time (e.g. &lt;time datetime=&quot;2021-12-15 12:22:00&quot;&gt;12:22&lt;/time&gt;), and also to make it machine-readable for any automated actions related to teh page (e.g. mark in a calendar)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;time datetime=&amp;quot;2021-12-15 12:22:00&amp;quot;&amp;gt;12:22&amp;lt;/time&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Mark&lt;/h4&gt;
&lt;p&gt;Used to &lt;mark&gt;highlight&lt;/mark&gt; a portion of text.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Used to &amp;lt;mark&amp;gt;highlight&amp;lt;/mark&amp;gt; a portion of text
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;What&#39;s next&lt;/h3&gt;
&lt;p&gt;Jumping back to the beginning, one of the important ideas mentioned in the podcast was that going forward we&#39;ll likely see
more elements and technologies supported by browsers that we&#39;re now using libraries for - think native browser support for variable
reactivity, modal dialogues, other markup languages and so on.&lt;/p&gt;
&lt;p&gt;The future is bright, but also the future is now.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Hitting The Books: Short Review Of The &quot;NoSQL Distilled&quot; Book</title>
        <link href="https://hydralien.net/blog//posts/nosql-distilled-book-review/"/>
        <updated>2021-12-16T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/nosql-distilled-book-review/</id>
        <content type="html">&lt;h3&gt;What Book?&lt;/h3&gt;
&lt;img src=&quot;https://martinfowler.com/books/nosql.jpg&quot; alt=&quot;NoSQL Distilled book cover&quot; style=&quot;max-width: 30%;&quot; /&gt;
&lt;p&gt;Another result of an effort to keep the personal knowledge base up-to-date (and a reference from another recent read,
&lt;a href=&quot;https://hydralien.net/blog//posts/nosql-distilled-book-review/building-microservices-book-review/&quot;&gt;Building Microservices&lt;/a&gt;) is the &lt;a href=&quot;https://martinfowler.com/books/nosql.html&quot;&gt;&amp;quot;NoSQL Distilled&amp;quot; book&lt;/a&gt;
by &lt;a href=&quot;https://martinfowler.com/&quot;&gt;Martin Fowler&lt;/a&gt; and &lt;a href=&quot;https://www.sadalage.com/menu/about/&quot;&gt;Pramod Sadalage&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&#39;s a fairly short and concise read of 152 pages, and it was published almost a decade ago in 2012 - which made me somewhat cautious
about how relevant and useful it is for the modern day systems.&lt;/p&gt;
&lt;h3&gt;General Impression&lt;/h3&gt;
&lt;p&gt;I&#39;ll start with a summary - the main idea of the book can be put as promoting the &lt;a href=&quot;https://martinfowler.com/bliki/PolyglotPersistence.html&quot;&gt;Polyglot Persistence&lt;/a&gt; - in the book&#39;s own words,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&amp;quot;Polyglot persistence is about using different data storage technologies to handle varying data storage needs&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To achieve the goal, the authors first cover basic principles of distributed systems such as distribution models, consistency,
data models and so on. After that they describe main types of the NoSQL storages: key-value, document, column-family and graph
(also mentioning some others like filesystem). The book finishes with a short guidance on the storage selection, which could be
summarized like this (quote from the book):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;The two main reasons to use NoSQL technology are:
- To improve programmer productivity by using a database that better matches an application&#39;s needs
- To improve data access performance via some combination of handling larger data volumes, reducing latency, and improving throughput.

It&#39;s essential to test your expectations about programmer productivity and/or performance before committing to use NoSQL technology.   
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&#39;s definitely much more than that in the book, namely the overview and suggestions of what&#39;s the best use cases for each storage type,
and what are the options of the specific storage systems (such as Riak, Cassandra, MongoDB, DynamoDB and so on).&lt;/p&gt;
&lt;p&gt;There&#39;s also a part that says that most of the application should still stick to relational DBs &amp;quot;at least until the NoSQL technology ecosystem becomes more mature&amp;quot;,
which after a decade of active usage and development it definitely is - but I think that consideration is still valid:
it&#39;s totally fine to use a relational database if it fits the data model (or if the data model is not clear yet).
I would definitely start with PostgreSQL for any common project, as it provides a lot of functionality in a very mature and highly supported package.&lt;/p&gt;
&lt;p&gt;One more important thought shared on those pages is to encapsulate the database work inside an abstraction - could be a class,
could be a service - to make switching storage if not smooth then at least possible in future (and likely transparent for the system&#39;s user.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;After almost 10 years of its publication, it&#39;s still impressively relevant and useful. And the format is really good - it&#39;s
very palatable and yet rich on ideas and details. There&#39;s certainly much more to learn about specific database technologies
(preferably by using them), but this book provides a great guidance on the basics and gives ideas on where to go next.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>MacOS Monterey Port 5000 Already In Use</title>
        <link href="https://hydralien.net/blog//posts/macos-port-5000-already-in-use/"/>
        <updated>2022-01-03T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/macos-port-5000-already-in-use/</id>
        <content type="html">&lt;h4&gt;Development port&lt;/h4&gt;
&lt;p&gt;Many web development frameworks are using some abstract port on local machine for development purposes, such as serving the
results (pages, API endpoints) locally for the testing/validation purposes. Those ports are usually chosen to be easy to remember,
for instance 8080, 8000, 3000, 5000 etc. And since (somewhat) standardised port range is only those below 1024, the port usage was always a bit of a chaos.&lt;/p&gt;
&lt;p&gt;The problem I faced recently was with a default development port (5000) suggested by Python &lt;a href=&quot;https://flask.palletsprojects.com/en/2.0.x/&quot;&gt;Flask framework&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;New conflict&lt;/h4&gt;
&lt;p&gt;I recently updated my laptop to OSX Monterey, and when trying to launch the Flask development server I faced the &amp;quot;&lt;em&gt;&lt;strong&gt;Port 5000 already in use&lt;/strong&gt;&lt;/em&gt;&amp;quot; error.
At first, I thought it might be a previous dev server instance hanging around, but looking at it with&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lsof -i tcp:5000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;showed that it&#39;s something else:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[halien@airhydra:~/devel]# lsof -i tcp:5000
COMMAND     PID   USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
ControlCe 18536 halien   19u  IPv4 0x4008cac8d519c5c9      0t0  TCP *:commplex-main (LISTEN)
ControlCe 18536 halien   20u  IPv6 0x4008cad72f646471      0t0  TCP *:commplex-main (LISTEN)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After some googling, turned out that OSX Control Center is now listening on port 5000 as an AirPlay server. According to the comments in &lt;a href=&quot;https://developer.apple.com/forums/thread/682332&quot;&gt;this thread&lt;/a&gt;, port 5000 usage for AirPlay is nothing new, it&#39;s just the OSX now supports it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Remote Audio Output Protocol, AKA AirTunes, AKA AirPlay, has been using port 5000 since the year 2004. This is nothing new.
All AirPlay receivers including AirPort Express and Apple TV use port 5000.
If you&#39;ve ever used Airfoil on your Mac (Airfoil Speakers was released in 2008), that also uses 5000 for the same reason.
AirPlay receiving is new to macOS Monterey, but AirPlay itself is very old, predating Flask and these other web development environments.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;The solution&lt;/h4&gt;
&lt;p&gt;A more robust solution would be to &lt;strong&gt;&lt;em&gt;use a different development port&lt;/em&gt;&lt;/strong&gt; - even a small change like using 5001 would do.
However, that could mean changing it in a lot of places, and if you&#39;re working in a team that could potentially
(depending on the collaboration setup) affect other developers.&lt;/p&gt;
&lt;p&gt;Another way is to &lt;em&gt;&lt;strong&gt;disable AirPlay server&lt;/strong&gt;&lt;/em&gt; via &lt;em&gt;&lt;strong&gt;System Preferences › Sharing&lt;/strong&gt;&lt;/em&gt;, and &lt;em&gt;&lt;strong&gt;unchecking AirPlay Receiver&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Problem With flutter_tts No Sound / Low Volume In iOS</title>
        <link href="https://hydralien.net/blog//posts/flutter-tts-ios-problem/"/>
        <updated>2022-01-14T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/flutter-tts-ios-problem/</id>
        <content type="html">&lt;h4&gt;The problem&lt;/h4&gt;
&lt;p&gt;I&#39;m using &lt;a href=&quot;https://pub.dev/packages/flutter_tts&quot;&gt;flutter_tts plugin&lt;/a&gt; for the text-to-speech capabilities in my &lt;a href=&quot;https://hydralien.net/pidging&quot;&gt;travel vocabulary app&lt;/a&gt;,
and it worked everywhere until recently - last time I tried building and deploying it, it worked everywhere &lt;strong&gt;except&lt;/strong&gt; iOS on device -
meaning Android emulator, Android device and iOS emulator were OK, but iOS device had no sound when trying to play the text.
From searching around, some folks report low volume problem which might be relevant.&lt;/p&gt;
&lt;h4&gt;The solution&lt;/h4&gt;
&lt;p&gt;I couldn&#39;t figure out when it started and what&#39;s causing it, so it took really a lot of googling till I finally found &lt;a href=&quot;https://gitanswer.com/flutter-tts-ios-sound-issue-dart-709710317&quot;&gt;a short thread&lt;/a&gt;
that described a solution:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; await flutterTts.setIosAudioCategory(IosTextToSpeechAudioCategory.playback, [
  IosTextToSpeechAudioCategoryOptions.defaultToSpeaker
]);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It should be done after creating the FlutterTTS instance and before playing. The important parts are both &lt;em&gt;IosTextToSpeechAudioCategory.playback&lt;/em&gt;
&lt;strong&gt;and&lt;/strong&gt; &lt;em&gt;IosTextToSpeechAudioCategoryOptions.defaultToSpeaker&lt;/em&gt; - I couldn&#39;t make it work without either of those.&lt;/p&gt;
&lt;p&gt;While I was at it, I&#39;ve also added several other flags to make it more future-proof and integrated with other audio being played,
as apparently the problem is in some defaults changing at some point, so the final solution looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let flutterTts = FlutterTts();
await flutterTts.setSharedInstance(true);
await flutterTts.setIosAudioCategory(IosTextToSpeechAudioCategory.playback,
    [
      IosTextToSpeechAudioCategoryOptions.allowBluetooth,
      IosTextToSpeechAudioCategoryOptions.allowBluetoothA2DP,
      IosTextToSpeechAudioCategoryOptions.mixWithOthers,
      IosTextToSpeechAudioCategoryOptions.defaultToSpeaker
    ],
    IosTextToSpeechAudioMode.defaultMode
);
&lt;/code&gt;&lt;/pre&gt;
</content>
    </entry>
    
    <entry>
        <title>Using JSON Web Tokens For Userless Mobile Authentication</title>
        <link href="https://hydralien.net/blog//posts/using-jwt-for-mobile-auth/"/>
        <updated>2022-01-29T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/using-jwt-for-mobile-auth/</id>
        <content type="html">&lt;h4&gt;The problem&lt;/h4&gt;
&lt;p&gt;For my &lt;a href=&quot;https://hydralien.net/pidging/&quot;&gt;travel vocabulary app Pidging&lt;/a&gt; (created with Flutter/Dart), I&#39;m using an API (written in Python)
that manages requests to actual translation service (Microsoft Azure Translator), cache results in memory and DB and also
manage a built-in vocabulary. There&#39;s no concept of user though, as all user-generated content remains on user device,
and server-side only caches translations.&lt;/p&gt;
&lt;p&gt;But even though the API is simple and no user info or content is exposed, I still want to protect it from being abused,
be able to control any unwanted user behavior and potentially store user data on server to remedy the situation where app is
removed and then reinstalled, or migrated to a new device.&lt;/p&gt;
&lt;h4&gt;Considerations&lt;/h4&gt;
&lt;p&gt;I thought about introducing user authentication, but I really don&#39;t want to impede the access or introduce any extra steps to
the app usage. So I decided to go with an identifier-based approach - but not with device id, because I don&#39;t control its
creation/change, and it also is considered a &lt;a href=&quot;https://en.wikipedia.org/wiki/Personal_data&quot;&gt;PII&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So I decided to generate app ID (&lt;a href=&quot;https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)&quot;&gt;UUID v4&lt;/a&gt;)
when app id launched for the first time, and store it in the keychain - as keychain content is the most persists content storage
on the phone, and I&#39;m not abusing it much (as I&#39;ll mention further on, there&#39;s also access and refresh tokens, but it&#39;s still
a negligible amount of data). I&#39;m using &lt;a href=&quot;https://pub.dev/packages/flutter_keychain&quot;&gt;https://pub.dev/packages/flutter_keychain&lt;/a&gt; to manage the process.&lt;/p&gt;
&lt;p&gt;The next consideration was to how to use it in the App-API communication. I first thought of doing something sophisticated
like generating cryptographic key pair on the app, register public key on the server and then pass encrypted tokens with the
API calls to ensure authentication. That would work (even though I&#39;d still need to maintain some token expiration mechanism),
but it was unnecessary complex and would involve bringing A LOT of dependencies. So I decided to keep the encryption to server
and just use a tried JWT (JSON Web Token) approach, which has established libraries in many languages (I&#39;m using &lt;a href=&quot;https://flask-jwt-extended.readthedocs.io/en/stable/&quot;&gt;Flask-JWT-Extended&lt;/a&gt;).&lt;/p&gt;
&lt;h4&gt;The flow&lt;/h4&gt;
&lt;p&gt;Currently, the logic sequence diagram looks like this (thx &lt;a href=&quot;https://sequencediagram.org/&quot;&gt;https://sequencediagram.org/&lt;/a&gt;):
&lt;img alt=&quot;Pidging JWT authentication/usage flow&quot; src=&quot;https://doc-00-48-docs.googleusercontent.com/docs/securesc/sfn07bucvovsn2io89pp0761preom1fu/s6g3ii4penu2gsr9l178dmj5g06kpu11/1643465475000/08697106004061146160/08697106004061146160/1QwW8iEP0KKmyS8oqmUY5AT5mswBFkLsR?authuser=0&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;Next steps&lt;/h4&gt;
&lt;p&gt;The next steps would be to utilize this mechanism not only for a stricter access control, but also to save/restore user data at the server side.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Hitting The Books: Short Review Of The &quot;Get Your Hands Dirty on Clean Architecture&quot; Book</title>
        <link href="https://hydralien.net/blog//posts/get-your-hands-dirty-on-clean-architecture-book-review/"/>
        <updated>2022-03-19T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/get-your-hands-dirty-on-clean-architecture-book-review/</id>
        <content type="html">&lt;h3&gt;What Book?&lt;/h3&gt;
&lt;img src=&quot;https://learning.oreilly.com/library/cover/9781839211966/250w/&quot; alt=&quot;Get Your Hands Dirty on Clean Architecture&quot; style=&quot;width: 20%; margin: 1em;&quot; /&gt;
&lt;p&gt;I recently started on a new software development position, and was immediately faced with an unexpected architectural choices - the team used something
called &amp;quot;&lt;a href=&quot;https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)&quot;&gt;Hexagonal Architecture&lt;/a&gt;&amp;quot; which was new to me.&lt;/p&gt;
&lt;p&gt;So I was suggested (among other materials) to read the &amp;quot;&lt;a href=&quot;https://www.goodreads.com/book/show/52774354-get-your-hands-dirty-on-clean-architecture&quot;&gt;Get Your Hands Dirty on Clean Architecture&lt;/a&gt;&amp;quot; book by &lt;a href=&quot;https://github.com/thombergs&quot;&gt;Tom Hombergs&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;General Impression&lt;/h3&gt;
&lt;p&gt;The gist of the idea could be simplified as &amp;quot;Dependency Inversion Everywhere&amp;quot; - meaning it heavily abstracts everything to interfaces/abstract clasees:
abstractions between API and business logic, abstractions between database (&amp;quot;persistent layer&amp;quot;) and business logic, abstractions between any external dependency and anything that uses it.&lt;/p&gt;
&lt;p&gt;The book heavily advocated for using this architecture, emphasizing that clear structure and abstractions galore would mean any changes would be isolated to a specific area and would not require
changing other places, such as replacing one DB with another or changing DB storage structure would not require changes anywhere else.&lt;/p&gt;
&lt;p&gt;To me (especially after few weeks working with a system designed over these principles) this all sounds nice but comes with a steep price:
build all the abstractions is a lot of extra work, and implementing adapters between layers is a lot of tedious boilerplate-creation work,
because it&#39;s mostly same-fields-to-same-fields, with maybe a few naming or type differences, but it all has to be clearly typed. And then the most common changes, such as adding new field to the data structure, would still require changes in ALL places, including several sets of tests implemented to test each side of abstraction.&lt;/p&gt;
&lt;p&gt;So to me, it&#39;s an extremist approach to the software architecture - structure is good, but too much structure means a sacrifice in velocity and fun, because following all the guidelines and rigid structure requirements is slow and sucks fun out of creation.&lt;/p&gt;
&lt;p&gt;Additionally, even though the author tries to point out that it&#39;s not the only way to create things, he immediately emphasises the benefits of this specific approach, which comes as a somewhat unbalanced opinion.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;I think it&#39;s an interesting read to understand another perspective and get familiar with ideas being used in software architecture today.
I don&#39;t necessarily agree with those ideas, or like the delivery - but some of the thoughts are valid, and reasonable usage of the dependency inversion is a useful practice.&lt;/p&gt;
&lt;p&gt;That said, it&#39;s good to understand and use the principles, but it&#39;s equally good to disregard them if the price is high but benefits are dubious - clear naming of classes and variables, comments at puzzling places
and &lt;strong&gt;some&lt;/strong&gt; structure in the code IMO brings 80% of the maintainability, with the rest being heavily opinionated and costly in learning for insignificant benefits.&lt;/p&gt;
&lt;p&gt;This might differ in larger scale though, when structural rigidity with component exchange flexibility means multiple teams could collaborate without causing each other troubles - but it contradicts the idea of service-oriented architecture,
when we&#39;re dividing responsibilities to a stand-alone services, and I like that approach much better (see my &lt;a href=&quot;https://hydralien.net/blog/posts/building-microservices-book-review/&quot;&gt;&amp;quot;Building Microservices&amp;quot; book review&lt;/a&gt;).&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Learning About Git Worktrees</title>
        <link href="https://hydralien.net/blog//posts/learning-about-git-worktrees/"/>
        <updated>2022-05-26T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/learning-about-git-worktrees/</id>
        <content type="html">&lt;h3&gt;Git Worktrees&lt;/h3&gt;
&lt;p&gt;A colleague of mine shared &lt;a href=&quot;https://www.maxpou.fr/git-worktrees&quot;&gt;his article about Git worktrees&lt;/a&gt; on the work chat, and I thought it&#39;s an interesting tool worth reflecting in my blog for own educational reasons.&lt;/p&gt;
&lt;p&gt;Essentially it&#39;s a way to work on several branches concurrently without a need to clone the whole repository, given that each branch is i a different (temporary) directory.
For instance, if I&#39;m currently working on a branch named &lt;code&gt;new-product-page&lt;/code&gt; and I need to change something in a &lt;code&gt;blog&lt;/code&gt; branch, I can do&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git worktree add ../blog-update blog
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to create a blog-update that would point to a &lt;code&gt;blog&lt;/code&gt; branch (I could also use &lt;code&gt;-b new-blog-branch&lt;/code&gt; to create a new branch).&lt;/p&gt;
&lt;p&gt;Then here&#39;s how it&#39;d look like in the listings:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;# git worktree list
/Users/halien/devel/my/hydralien.net  1ec7851 [new-product-page]
/Users/halien/devel/my/blog-update    483c934 [blog]

&amp;gt;# git branch
+ blog
  master
* new-product-page
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And when the changes in the worktree are done, and it&#39;s no longer required, removing it is as easy as&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git worktree remove blog-update
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&#39;s also an official documentation page for it: &lt;a href=&quot;https://git-scm.com/docs/git-worktree&quot;&gt;https://git-scm.com/docs/git-worktree&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Robo 3T / Robomongo export to CSV and returning more than 50 records</title>
        <link href="https://hydralien.net/blog//posts/robo3t-robomongo-export-to-csv-and-return-over-50-records/"/>
        <updated>2022-05-28T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/robo3t-robomongo-export-to-csv-and-return-over-50-records/</id>
        <content type="html">&lt;h3&gt;What problems&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://robomongo.org/&quot;&gt;Robo 3T&lt;/a&gt; (aka Robomongo) is a simple little query tool for MongoDB.
It&#39;s perhaps not crazy convenient, and it looks like MySQL tools used to look about a decade ago, but it does its job well, and it&#39;s free.&lt;/p&gt;
&lt;p&gt;Due to its simplicity some functionality is either not there, or it&#39;s unclear how to get it. Two problems I faced recently were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How to return more than default 50 records&lt;/li&gt;
&lt;li&gt;How to export returned records to CSV&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;What solutions&lt;/h3&gt;
&lt;h4&gt;50 records limit&lt;/h4&gt;
&lt;p&gt;The more-than-50-records problem had a fairly straightforward solution: add a batch size declaration before the query:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DBQuery.shellBatchSize = 500;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So setting this to something really high does the trick.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; it&#39;s persistent, so to return it to 50 you need to set it to 50 explicitly, otherwise it&#39;d use the defined batch size even when the declaration is removed.&lt;/p&gt;
&lt;h4&gt;Export to CSV&lt;/h4&gt;
&lt;p&gt;This other problem of getting results in CSV format was more interesting - at first I tried to find online services for that, though most of the JSON-to-CSV solutions only work with a complete JSON object (and not separate JSON blobs per document).
There&#39;s one resource that supports this case - this &lt;a href=&quot;https://data.page/json/csv&quot;&gt;JSON to CSV Converter&lt;/a&gt; - but it starts asking for money pretty quick, and its copy-to-clipboard function seems to be broken.&lt;/p&gt;
&lt;p&gt;After some extra search, turned out that there&#39;s a way of extending Robo 3T functionality with Javascript, so missing functionality could be added to it (to some extent).&lt;/p&gt;
&lt;p&gt;Essentially if a file &lt;code&gt;.robomongorc.js&lt;/code&gt; exists in home directory, Robo 3T will execute it on start (so restart it to load it), and the functions defined in this file will be available for the query processing.&lt;/p&gt;
&lt;p&gt;From the &lt;a href=&quot;https://github.com/Studio3T/robomongo/wiki/How-to-export-to-CSV&quot;&gt;article on Studio3T wiki&lt;/a&gt;, adding the following function to &lt;code&gt;~/.robomongorc.js&lt;/code&gt; file adds a CVS conversion functionality:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Export to CSV function
function toCSV (deliminator, textQualifier)
{
var count = -1;
var headers = [];
var data = {};

    var cursor = this;

    deliminator = deliminator == null ? &#39;,&#39; : deliminator;
    textQualifier = textQualifier == null ? &#39;&#92;&amp;quot;&#39; : textQualifier;

    while (cursor.hasNext()) {

        var array = new Array(cursor.next());

        count++;

        for (var index in array[0]) {
            if (headers.indexOf(index) == -1) {
                headers.push(index);
            }
        }

        for (var i = 0; i &amp;lt; array.length; i++) {
            for (var index in array[i]) {
                data[count + &#39;_&#39; + index] = array[i][index];
            }
        }
    }

    var line = &#39;&#39;;

    for (var index in headers) {
        line += textQualifier + headers[index] + textQualifier + deliminator;
    }

    line = line.slice(0, -1);
    print(line);

    for (var i = 0; i &amp;lt; count + 1; i++) {

        var line = &#39;&#39;;
        var cell = &#39;&#39;;
        for (var j = 0; j &amp;lt; headers.length; j++) {
            cell = data[i + &#39;_&#39; + headers[j]];
            if (cell == undefined) cell = &#39;&#39;;
            line += textQualifier + cell + textQualifier + deliminator;
        }

        line = line.slice(0, -1);
        print(line);
    }
}
DBQuery.prototype.toCSV=toCSV; //regular find
DBCommandCursor.prototype.toCSV=toCSV; //aggregates
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To use it, add &lt;code&gt;.toCSV()&lt;/code&gt; at the end of the query, like e.g.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;db.getCollection(&#39;somecollection&#39;).find({}).toCSV()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Neat!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>ASAP is a swear word</title>
        <link href="https://hydralien.net/blog//posts/asap-is-a-swear-word/"/>
        <updated>2022-05-29T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/asap-is-a-swear-word/</id>
        <content type="html">&lt;p&gt;The &lt;a href=&quot;https://www.urbandictionary.com/define.php?term=asap&quot;&gt;ASAP&lt;/a&gt; acronym is something I have a strong opinion about.
I haven&#39;t encountered it in a work relationship for quite a while (and was very happy about it), but it reared its ugly head recently, and so I decided to put my opinion into words to understand it better myself.&lt;/p&gt;
&lt;p&gt;Resorting to the usage of ASAP in professional communication is similar to resorting to violence when resolving problems in personal communication - it&#39;s a tool that should never be used, yet it&#39;s really easy to use and thus can be appealing.
It&#39;s an imperative top-down application of unquestionable urgency that doesn&#39;t allow any space for discussion.
It also comes hand-in-hand with the mentality of &amp;quot;bringing the solutions&amp;quot; management approach, when managers are telling people what to do and often also how to do it, hence when something doesn&#39;t go according to plan, addressing the issue also becomes an imperative command instead of raising and relying on employees&#39; situational awareness.&lt;/p&gt;
&lt;p&gt;There are much better ways of getting things done quickly, such as helping employees to understand the project plans and problems, maintain open and two-way communication and feedback channel and share the decisions, plans, problems and their background, so that everyone could relate to the product and act on solving problems vast on their own volition, and recognise and address the priorities.
Apart from making people more informed and thus making more relevant decision when building the product, it also raises the responsibility and passion for the things they do, for the product they build and a loyalty to the company - while telling people to do things ASAP does the very opposite.&lt;/p&gt;
&lt;p&gt;So no ASAP, please. Let&#39;s raise awareness and prioritise things together instead.&lt;/p&gt;
&lt;p&gt;P.S.: Also promoted on &lt;a href=&quot;https://meetingless.io/against-asap&quot;&gt;https://meetingless.io/against-asap&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Flutter iOS App Building Problem &quot;CocoaPods requires your terminal to be using UTF-8 encoding&quot;</title>
        <link href="https://hydralien.net/blog//posts/flutter-cocoapods-require-utf8/"/>
        <updated>2022-05-30T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/flutter-cocoapods-require-utf8/</id>
        <content type="html">&lt;h4&gt;The problem&lt;/h4&gt;
&lt;p&gt;After another update, trying to build Flutter app for iOS started throwing an error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WARNING: CocoaPods requires your terminal to be using UTF-8 encoding.
Consider adding the following to ~/.profile:

export LANG=en_US.UTF-8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And refusing to build.&lt;/p&gt;
&lt;p&gt;After some search and failing attempts to solve it, I finally managed to get it right.
Basically as &lt;a href=&quot;https://github.com/CocoaPods/CocoaPods/issues/6333#issuecomment-866591220&quot;&gt;this bugreport says&lt;/a&gt;,
&lt;code&gt;~/.bash_profile&lt;/code&gt; or &lt;code&gt;~/.zshrc&lt;/code&gt; (depending on default shell) should be updated with following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8
export LC_ALL=en_US.UTF-8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tricky parts are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;error message mentions only &lt;code&gt;LANG=en_US.UTF-8&lt;/code&gt;, but it actually should be all 3&lt;/li&gt;
&lt;li&gt;it has to be in &lt;code&gt;~/.bash_profile&lt;/code&gt; and &lt;strong&gt;NOT&lt;/strong&gt; in &lt;code&gt;~/.profile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.bash_profile&lt;/code&gt; has to be functional (try it with &lt;code&gt;source ~/.bash_profile&lt;/code&gt; and see that variables were set) - in my case it was long neglected because I mostly used &lt;code&gt;~/.profile&lt;/code&gt; and so it was not operational till I removed unused stuff&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hope I remember this blog post next time it happens, as this is already a second time and I had to Google it all over again.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Sequence Diagrams Overview</title>
        <link href="https://hydralien.net/blog//posts/sequence-diagram-overview/"/>
        <updated>2022-06-04T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/sequence-diagram-overview/</id>
        <content type="html">&lt;h3&gt;Sequence Diagrams&lt;/h3&gt;
&lt;p&gt;...or another article to address the problem of desperately searching for something because I can&#39;t recall how it&#39;s called 🤣&lt;/p&gt;
&lt;p&gt;So I sometimes need to display a workflow or a chain of events in the software system (or any system or a set of), and then I remember that &amp;quot;there&#39;s this sthing with a parallel lines connected with arrows&amp;quot;.&lt;/p&gt;
&lt;p&gt;That thing is a &lt;a href=&quot;https://en.wikipedia.org/wiki/Sequence_diagram&quot;&gt;Sequence Diagram&lt;/a&gt;, and, to quote the Wikipedia article,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It depicts the processes involved and the sequence of messages exchanged between the processes needed to carry out the functionality&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are various ways and tools to create one, and some more elaborate diagram tools have it in their arsenal - though I find this resource most convenient:
&lt;a href=&quot;https://sequencediagram.org/&quot;&gt;https://sequencediagram.org/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It lets to create the diagram with a sequence of simple command, adding entities automatically as they&#39;re mentioned in commands, e.g.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;title Sequence Diagram Example
UI-&amp;gt;API:request user data
API-&amp;gt;DB:get data from DB
DB-&amp;gt;API:return data
API-&amp;gt;UI:return user structure
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which displays&lt;/p&gt;
&lt;img src=&quot;https://hydralien.net/blog/assets/sequence_diagram_example.png&quot; alt=&quot;Sequence Diagram Example&quot; /&gt;
&lt;p&gt;What&#39;s nice is this tool allows me to be as simple or as sophisticated as I want - there&#39;s a lot of bells and whistles available,
such as various line types, notes, colors, icons, interactive elements and so on: &lt;a href=&quot;https://sequencediagram.org/instructions.html&quot;&gt;https://sequencediagram.org/instructions.html&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Introducing Picturevert: An Image Color Inversion App</title>
        <link href="https://hydralien.net/blog//posts/picturevert-intro/"/>
        <updated>2022-06-19T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/picturevert-intro/</id>
        <content type="html">&lt;h4&gt;The app&lt;/h4&gt;
&lt;img src=&quot;https://hydralien.net/blog/assets/picturevert_logo.png&quot; alt=&quot;Picturevert logo&quot; style=&quot;width: 150px; border-radius: 1em;&quot; /&gt;
&lt;p&gt;It&#39;s a fairly small thing - a one-page app that loads a picture from photo gallery, inverts the colors and allows to store the result back to gallery.&lt;/p&gt;
&lt;p&gt;Built for two reasons - first, I wanted to update my Flutter/Dart experience a bit, as I haven&#39;t dome much with it since releasing &lt;a href=&quot;https://hydralien.net/pidging&quot;&gt;Pidging&lt;/a&gt;;
but in addition to that, I wanted a tool to make photo negatives out of my photos (because it looks cool and entirely strange), and I couldn&#39;t find anything suitable and free available.&lt;/p&gt;
&lt;p&gt;So here it is, &lt;a href=&quot;https://hydralien.net/picturevert&quot;&gt;the Picturevert&lt;/a&gt; - I&#39;m in the process of uploading it to the app stores (it&#39;s always a huge pain), but once I do it will be freely available there.&lt;/p&gt;
&lt;p&gt;Oh, and its code is also free (though not very pretty): &lt;a href=&quot;https://github.com/hydralien/PictureVert&quot;&gt;https://github.com/hydralien/PictureVert&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Preparing Flutter App For Android Release (Google Play)</title>
        <link href="https://hydralien.net/blog//posts/preparing-flutter-app-for-android-release/"/>
        <updated>2022-06-19T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/preparing-flutter-app-for-android-release/</id>
        <content type="html">&lt;h4&gt;The Problem&lt;/h4&gt;
&lt;p&gt;Flutter app is surprisingly unprepared for the production release on Google Play - the iOS release is a relatively straightforward matter,
where XCode (mostly) tells you what&#39;s missing, while Android app happily builds but then Google Play store starts throwing errors like
&amp;quot;&lt;em&gt;You uploaded an APK or Android App Bundle that was signed in debug mode&lt;/em&gt;&amp;quot; or &amp;quot;&lt;em&gt;Keystore file not set for signing config release&lt;/em&gt;&amp;quot;.&lt;/p&gt;
&lt;p&gt;So here&#39;s what needs to be done.&lt;/p&gt;
&lt;h4&gt;The Solution&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;android/app/build.gradle&lt;/code&gt; should have &lt;code&gt;defaultConfig.applicationId&lt;/code&gt; set to actual identifier, like e.g. &lt;code&gt;net.hydralien.pictuvert&lt;/code&gt; - otherwise the store will complain that it&#39;s unavailable.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you&#39;re uploading a new build, it&#39;s number should be incremented after &amp;quot;+&amp;quot; in &lt;code&gt;pubspec.yaml&lt;/code&gt; (e.g. &amp;quot;version: 1.0.0+1&amp;quot;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;android/key.properties&lt;/code&gt; file should exist (it&#39;s hidden from the version control), and have e.g.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;storePassword=YourPassword
keyPassword=YourPassword
keyAlias=upload
storeFile=/Users/halien/upload-keystore.jks
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;android/app/build.gradle&lt;/code&gt; should have keystore definition at the top, before &amp;quot;android&amp;quot; section:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  def keystoreProperties = new Properties()
  def keystorePropertiesFile = rootProject.file(&#39;key.properties&#39;)
  if (keystorePropertiesFile.exists()) {
      keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;it also needs to define prod signing config before &amp;quot;buildTypes&amp;quot; section, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  signingConfigs {
      release {
          keyAlias keystoreProperties[&#39;keyAlias&#39;]
          keyPassword keystoreProperties[&#39;keyPassword&#39;]
          storeFile keystoreProperties[&#39;storeFile&#39;] ? file(keystoreProperties[&#39;storeFile&#39;]) : null
          storePassword keystoreProperties[&#39;storePassword&#39;]
      }
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;and then inside the &amp;quot;buildTypes&amp;quot; section, &lt;code&gt;igningConfig signingConfigs.debug&lt;/code&gt; should be changed to &lt;code&gt;igningConfig signingConfigs.release&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With all that in place, running &lt;code&gt;flutter build appbundle&lt;/code&gt; should produce a valid production-signed bundle at &lt;code&gt;build/app/outputs/bundle/release/app-release.aab&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Hope this saves me some time next time I face this.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Include Git Commit Id In Docker Container Build</title>
        <link href="https://hydralien.net/blog//posts/docker-include-git-commit-id-in-build/"/>
        <updated>2022-07-08T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/docker-include-git-commit-id-in-build/</id>
        <content type="html">&lt;h4&gt;The Problem&lt;/h4&gt;
&lt;p&gt;When working on containerizing an API service with Docker for the CI/CD pipeline, I needed to include into container
current Git commit ID and branch - so I could know what code is running in production by just asking the API to return these values.&lt;/p&gt;
&lt;p&gt;Essentially there are two simple ways to do it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;store anv variables in a .env file, which would be easily recognisable by modules like &lt;a href=&quot;https://www.npmjs.com/package/dotenv&quot;&gt;dotenv&lt;/a&gt; for Node.js architecture
or &lt;a href=&quot;https://pypi.org/project/python-dotenv/&quot;&gt;python-dotenv&lt;/a&gt; in Python.&lt;/li&gt;
&lt;li&gt;set them into regular environment variables with &lt;a href=&quot;https://docs.docker.com/engine/reference/builder/#env&quot;&gt;Dockerfile ENV instruction&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first is kinda simpler to implement and looks contained to Dockerfile (becasue I can bake Git commands and file creation inside Dockerfile),
but has several downsides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it requires loading .git inside Docker image, even if only for build stage - it takes time. And it&#39;s easy to let the whole repo to slip through into container image.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;.git&lt;/em&gt; might be restricted in &lt;em&gt;.dockerignore&lt;/em&gt;, and removing it from there might have undesirable consequences later.&lt;/li&gt;
&lt;li&gt;storing things in .env promotes storing env in file, which is not too bad for a git commit ID, but a larger potential security issue for credentials.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;The Solution&lt;/h4&gt;
&lt;p&gt;So I chose to store in env variables, which required following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Specifying input parameters via &lt;a href=&quot;https://docs.docker.com/engine/reference/builder/#arg&quot;&gt;ARG instruction&lt;/a&gt;, like so:&lt;pre&gt;&lt;code&gt;ARG GIT_COMMIT_BRANCH
ARG GIT_COMMIT_ID
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Setting them into environment variables inside the container image:&lt;pre&gt;&lt;code&gt;ENV GIT_COMMIT_BRANCH=$GIT_COMMIT_BRANCH
ENV GIT_COMMIT_ID=$GIT_COMMIT_ID
&lt;/code&gt;&lt;/pre&gt;
&lt;strong&gt;Note&lt;/strong&gt;: if you have several stages in Dockerfile, ARG and ENV should be at the same stage as final CMD instruction.&lt;/li&gt;
&lt;li&gt;Identifying Git commands to get branch name and commit ID:&lt;pre&gt;&lt;code&gt;git branch --show-current
git rev-parse --short HEAD
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;provide arg values as input parameters for &lt;code&gt;docker build&lt;/code&gt;, like so:&lt;pre&gt;&lt;code&gt;docker build --build-arg GIT_COMMIT_BRANCH=`git branch --show-current` --build-arg GIT_COMMIT_ID=`git rev-parse --short HEAD` -t containername
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And that did it - I get the required information when launching docker build inside Git repository,
where I invariably have repository information, and pass it to the build process that bakes it into the container image
so it stays the same for each instance and is available for the application code inside container to use however it pleases.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Docker Build - Include Files Outside The Build Context</title>
        <link href="https://hydralien.net/blog//posts/docker-include-files-outside-build-context/"/>
        <updated>2022-10-02T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/docker-include-files-outside-build-context/</id>
        <content type="html">&lt;h4&gt;The Problem&lt;/h4&gt;
&lt;p&gt;When building a Docker image, and trying to include files from a directory outside current context (context being where Dockerfile is), e.g.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    COPY ../code/ ./
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;the build fails with a &lt;code&gt;Forbidden path outside the build context&lt;/code&gt; error.&lt;/p&gt;
&lt;p&gt;There&#39;s not often a case for this, but my circumstances were that I had an app with several interconnected parts,
and needed to run a part of it as a kind of &amp;quot;cronjobs&amp;quot; (one-off launch), and the other part as a web server.
So I needed two different Dockerfiles, but also some helping scripts for both - keeping it all in one directory could be possible, but a bit messy.
Besides, I&#39;d still need to specify which Dockerfile to use for which build.&lt;/p&gt;
&lt;h4&gt;The Solution&lt;/h4&gt;
&lt;p&gt;The trick is to change the context (as also described &lt;a href=&quot;https://www.jamestharpe.com/docker-include-files-outside-build-context/&quot;&gt;in this article&lt;/a&gt;),
and to essentially run &lt;code&gt;docker build&lt;/code&gt; inside the directory where required files are.&lt;/p&gt;
&lt;p&gt;So if, for instance, I want to keep Dockerfile in &lt;code&gt;images/&lt;/code&gt; directory but get files from the &lt;code&gt;code/&lt;/code&gt; (but both are at the same hierarchy level),
I edit the Dockerfile to include files from current directory:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    COPY ./code/ ./
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then run build from the one directory up, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    docker build -t node-app -f images/Dockerfile .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Success!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Useful IntelliJ Idea Shortcuts (For OSX)</title>
        <link href="https://hydralien.net/blog//posts/intellij-idea-shortcuts/"/>
        <updated>2022-10-14T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/intellij-idea-shortcuts/</id>
        <content type="html">&lt;h3&gt;WIP&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;This page is updated now and then when I find new useful shortcuts&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;What Shortcuts&lt;/h4&gt;
&lt;p&gt;I&#39;ve started using the &lt;a href=&quot;https://www.jetbrains.com/idea/&quot;&gt;IntelliJ Idea&lt;/a&gt; several years ago when a colleague of mine strongly suggested it&#39;d be way more effective way of writing code,
especially for a strongly typed languages. And it definitely was (well, at least comparing to the Emacs I&#39;ve mostly used before).
I&#39;ve been using it ever since, and it&#39;s definitely worthy the annual subscription.&lt;/p&gt;
&lt;p&gt;One thing that makes IDEs powerful is the keyboard shortcuts, and there&#39;s usually a plenty - and Idea is no exception.
I&#39;ve been using some of them from day one, created or modified a few but then thought that I&#39;m probably not using (and don&#39;t even know about)
some other useful built-in shortcuts.&lt;/p&gt;
&lt;p&gt;So I went through some articles about the subject and gathered me a list of shortcuts I should start using, for they are handy.
Posting the list here mostly for my own reference (it&#39;s easier to manage than a piece of paper the list is currently on).&lt;/p&gt;
&lt;p&gt;The shortcuts here are for OSX only, although I believe it&#39;s not hard to map them to PC keyboard. Also there&#39;s no order to them.&lt;/p&gt;
&lt;h4&gt;The List (in no specific order)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌘⇧V&lt;/span&gt; History of copy-paste buffer. I have similar thing in OSX (thx &lt;a href=&quot;https://www.alfredapp.com/&quot;&gt;Albert&lt;/a&gt;),
but it&#39;s useful to have something specific to IDE to see specific code-related items.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌥⇧M&lt;/span&gt; &lt;a href=&quot;https://plugins.jetbrains.com/plugin/2162-string-manipulation&quot;&gt;String manipulation plugin&lt;/a&gt; -
not a standard thing (meaning it must be installed separately as an add-on), but it&#39;s worth having for the functionality it provides.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;&lt;em&gt;Fn&lt;/em&gt;⌥&lt;em&gt;F7&lt;/em&gt;&lt;/span&gt; Usage of the current thing in code; same as ⌘+click, but easier to navigate to explore multiple entries.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌘B&lt;/span&gt; Jump to the declaration of the current thing.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌘E&lt;/span&gt; Recently visited files (you can also type to filter).&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌘⇧E&lt;/span&gt; Recently visited locations (specific places in code).&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌃T&lt;/span&gt; &amp;quot;Refactor this&amp;quot; context menu.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌃⇧J&lt;/span&gt; Join multiple lines - useful to concatenate strings or make code a one-liner.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌥&lt;em&gt;Enter&lt;/em&gt;&lt;/span&gt; Context help actions.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌘&lt;em&gt;Backspace&lt;/em&gt;&lt;/span&gt; Remove current line (also ⌘+X without selection cuts the entire line to buffer).&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌘&lt;em&gt;Fn&lt;/em&gt; &lt;em&gt;F12&lt;/em&gt;&lt;/span&gt; Class/file structure roster.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;&lt;em&gt;Fn&lt;/em&gt; ⇧&lt;em&gt;F2&lt;/em&gt;&lt;/span&gt; Jump to the next problem in the code.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;&lt;em&gt;Fn&lt;/em&gt; ⇧&lt;em&gt;F6&lt;/em&gt;&lt;/span&gt; Rename current thing (with propagation to all usage cases).&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌘D&lt;/span&gt; Duplicate current line.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌃⇧↑ &lt;em&gt;or&lt;/em&gt; ⌃⇧↓&lt;/span&gt; Move to the previous/next block start.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌥⇧↑ &lt;em&gt;or&lt;/em&gt; ⌥⇧↓&lt;/span&gt; Move current line up/down.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌥↑ &lt;em&gt;or&lt;/em&gt; ⌥↓&lt;/span&gt; Select increasingly larger/smaller block of code.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌘[ &lt;em&gt;or&lt;/em&gt; ⌘]&lt;/span&gt; Jump to previous/next visited place.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌥⌘[ &lt;em&gt;or&lt;/em&gt; ⌥⌘]&lt;/span&gt; Jump to next/previous matching parenthesis/bracket.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌘⇧O&lt;/span&gt; Search for files in project (type random parts of file name and it&#39;ll find it!).&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌘⇧F&lt;/span&gt; Search for text in project.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌘⇧C&lt;/span&gt; Copy the current file path. It&#39;s not necessarily useful as it copies the path from root, which is not always desirable.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌘⌥⇧C&lt;/span&gt; So there&#39;s also &amp;quot;Copy Reference&amp;quot; which copies a relative path to file plus line number. Which is nice, but also not quite the thing.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌘+ / -&lt;/span&gt; Expand (+) or collapse (-) current code block. &lt;span class=&quot;keyboard-shortcut&quot;&gt;⌘⌥+ / -&lt;/span&gt; does the same for the whole current file.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;keyboard-shortcut&quot;&gt;⌘ b&lt;/span&gt; Jump to the current entity declaration (same as ⌘-click). &lt;span class=&quot;keyboard-shortcut&quot;&gt;⌥⌘ b&lt;/span&gt; jumps to implementation.&lt;/li&gt;
&lt;li&gt;So there are more shortcuts that could be configured: &lt;strong&gt;&amp;quot;Path from repository root&amp;quot;&lt;/strong&gt; and - most impressive - &lt;strong&gt;&amp;quot;Github Repository URL&amp;quot;&lt;/strong&gt;, which copies a link with a line reference.
These need to be configured manually in &lt;em&gt;Settings -&amp;gt; Keymap&lt;/em&gt;: &lt;br /&gt;&lt;img src=&quot;https://hydralien.net/blog/assets/ijidea_path_config.png&quot; alt=&quot;Path copy keyboard shortcuts&quot; style=&quot;width: 90%&quot; /&gt;.&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <title>Shit Yourself In The Food</title>
        <link href="https://hydralien.net/blog//posts/shit-yourself-in-the-food/"/>
        <updated>2022-10-18T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/shit-yourself-in-the-food/</id>
        <content type="html">&lt;p&gt;A more fecal version of &amp;quot;&lt;a href=&quot;https://www.urbandictionary.com/define.php?term=Shoot%20yourself%20in%20the%20foot&quot;&gt;Shoot yourself in the foot&lt;/a&gt;&amp;quot;.
Just saying.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>On Importance Of HTTP Redirect In Single-Page Applications</title>
        <link href="https://hydralien.net/blog//posts/on-importance-of-http-redirect-in-spa/"/>
        <updated>2022-11-05T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/on-importance-of-http-redirect-in-spa/</id>
        <content type="html">&lt;h4&gt;The Important Part&lt;/h4&gt;
&lt;p&gt;Single-Page Applications (SPA) are by design operating within the scope of one entry point (URL).
Though they usually do have pages (or screens or other ways to structure interfaces and information), and they do have a way of navigating through them
via various routing libraries (e.g &lt;a href=&quot;https://reactrouter.com/en/main&quot;&gt;https://reactrouter.com/en/main&lt;/a&gt; or &lt;a href=&quot;https://router.vuejs.org/&quot;&gt;https://router.vuejs.org/&lt;/a&gt;)
that also manages (and reacts to changes in) &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/History_API&quot;&gt;browser&#39;s history API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The problem with that is the entry point: as long as the app is loaded, changes in URL in browser&#39;s history do not require page reload,
and the application&#39;s code reacts to them and displays the page accordingly.
But when the URL is loaded anew (or the whole page is reloaded in browser), the HTTP request goes to the new entry point which is just not there.&lt;/p&gt;
&lt;h4&gt;An example&lt;/h4&gt;
&lt;p&gt;Let&#39;s say I have an SPA on my website, which is served from &lt;code&gt;index.html&lt;/code&gt; - meaning there&#39;s an index.html that launches JS code for the app.
So because web servers interpret &lt;code&gt;index.html&lt;/code&gt; as a default content for the directory, requests to &lt;code&gt;https://mysite.net/&lt;/code&gt; would serve &lt;code&gt;index.html&lt;/code&gt; and everything would work.&lt;/p&gt;
&lt;p&gt;Now if I have a &amp;quot;Contacts&amp;quot; tab in my SPA that uses &lt;code&gt;/contacts&lt;/code&gt; path for routing, while SPA is open and manages the browser history
its router will handle &lt;code&gt;https://mysite.net/contacts&lt;/code&gt; and it will work. But when URL is (re)loaded by browser, it will ask the webserver for
&lt;code&gt;/contacts&lt;/code&gt; - and there&#39;s no such file on the webserver, so it will result in 404.&lt;/p&gt;
&lt;h4&gt;Things to remember&lt;/h4&gt;
&lt;p&gt;So unless there&#39;s a server-side rendering involved, SPA need rewrite rules on server to serve &lt;code&gt;index.html&lt;/code&gt; on every URL,
so the SPA could launch and its router could take care or URL parsing and displaying the desired page/tab.&lt;/p&gt;
&lt;p&gt;Vue docs have a good selection of recipes for various web-servers: https://router.vuejs.org/guide/essentials/history-mode.html#example-server-configurations - for instance,
for Apache it&#39;d be adding following to &lt;code&gt;.htaccess&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &amp;lt;IfModule mod_rewrite.c&amp;gt;
        RewriteEngine On
        RewriteBase /
        RewriteRule ^index&#92;.html$ - [L]
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule . /index.html [L]
    &amp;lt;/IfModule&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;for Nginx&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    location / {
        try_files $uri $uri/ /index.html;
    }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For Node with Express &lt;a href=&quot;https://github.com/bripkens/connect-history-api-fallback&quot;&gt;could be a middleware&lt;/a&gt; and so on.&lt;/p&gt;
&lt;p&gt;In Netlify case, there&#39;s also a dedicated documentation page for rewrites: https://docs.netlify.com/routing/redirects/rewrites-proxies/ - but in short,
you need following in &lt;code&gt;_redirects&lt;/code&gt; file in SPA root (make sure it&#39;s copied to target directory on build):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    /*    /index.html   200
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IMPORTANT: if you&lt;/p&gt;
&lt;p&gt;Good thing would be to know about it before it hits you, though being able to quickly solve it after the fact (like what made me write this) is OK too 😄&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Ideas For Remote Teams</title>
        <link href="https://hydralien.net/blog//posts/remote-team-collaboration-ideas/"/>
        <updated>2022-11-19T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/remote-team-collaboration-ideas/</id>
        <content type="html">&lt;p&gt;A new article on &lt;a href=&quot;https://meetingless.io/&quot;&gt;meetingless.io&lt;/a&gt; about working remotely and how to make it better for everyone involved: &lt;a href=&quot;https://meetingless.io/remote-collaboration&quot;&gt;https://meetingless.io/remote-collaboration&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I&#39;ve been working on remote and hybrid teams ever since the beginning of the pandemic - much like many of us,
though because I switched several teams and companies along the way and had various insights from friends and colleagues,
I decided to put some thoughts together and publish them for the potential future reference (and generally to organise thoughts in my head).&lt;/p&gt;
&lt;p&gt;It&#39;s not a comprehensive guide - in fact, it&#39;s not a guide at all: it&#39;s a short collection of (maybe a bit random) thoughts and ideas that I experienced or observed working in real life.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Everybody Nose</title>
        <link href="https://hydralien.net/blog//posts/everybody-nose/"/>
        <updated>2022-11-28T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/everybody-nose/</id>
        <content type="html">&lt;p&gt;Since one of the benefits of my current employment is the free 1-year subscription to Adobe Creative Cloud,
I decided to enjoy that and shake dust off my (very) rudimentary Photoshop skills.&lt;/p&gt;
&lt;p&gt;The result is a visualisation of the &amp;quot;Everybody Nose&amp;quot; word play:&lt;/p&gt;
&lt;img src=&quot;https://hydralien.net/blog/assets/nose.jpg&quot; alt=&quot;Everybody Nose&quot; style=&quot;width: 90%&quot; /&gt;
</content>
    </entry>
    
    <entry>
        <title>Meter And Progress HTML Elements Demo Using SolidJS</title>
        <link href="https://hydralien.net/blog//posts/meter-and-progress-html-elements-with-solidjs/"/>
        <updated>2023-01-06T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/meter-and-progress-html-elements-with-solidjs/</id>
        <content type="html">&lt;h3&gt;Why&lt;/h3&gt;
&lt;p&gt;As someone who started dealing with HTML since it was (IIRC) version 3.2, much of my knowledge and usage of the HTML tags
dates back if not to 1998 then to 2004 for sure - like, it&#39;s still easier for me to think page structure in tables than in grid and flex.&lt;/p&gt;
&lt;p&gt;Nonetheless, when I encounter a new tag, it&#39;s always fascinating to gie it a try - even if it&#39;s not immediately useful.
So when I read about &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meter&quot;&gt;&lt;code&gt;&amp;lt;meter&amp;gt;&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress&quot;&gt;&lt;code&gt;&amp;lt;progress&amp;gt;&lt;/code&gt;&lt;/a&gt; tags,
I decided to do a little interactive demo out of those.
I originally wanted to use Svelte, but since this blog is essentially Markdown rendered by 11ty, that would require
changing template engine for one page, so maybe some other day. Instead, I remembered about &lt;a href=&quot;https://www.solidjs.com/guides/getting-started&quot;&gt;SolidJS&lt;/a&gt;
and it seemed like a good option so here we are.&lt;/p&gt;
&lt;p&gt;There&#39;s deliberately very little styling involved, the only thing that&#39;s applied is&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    meter, progress {
        width: 500px;
        height: 50px;
    }
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Meter&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;meter&amp;gt;&lt;/code&gt; is intended for a metric-like information display, a number that could go up and down and have a different states (high/low).&lt;/p&gt;
&lt;p&gt;The thresholds are specified with  min, max, low, optimum and high parameters, like e.g.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &amp;lt;meter value=&amp;quot;20&amp;quot; min=&amp;quot;0&amp;quot; max=&amp;quot;100&amp;quot; low=&amp;quot;25&amp;quot; optimum=&amp;quot;50&amp;quot; high=&amp;quot;75&amp;quot; id=&amp;quot;metric-display&amp;quot; title=&amp;quot;Meter Demo&amp;quot;/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;meter-demo&quot;&gt;&lt;/div&gt;
&lt;p&gt;To quickly see the different states, you could &lt;button class=&quot;set-metric&quot; value=&quot;50&quot;&gt;set it to 50&lt;/button&gt;
or &lt;button class=&quot;set-metric&quot; value=&quot;90&quot;&gt;set it to 90&lt;/button&gt; or &lt;button class=&quot;set-metric&quot; value=&quot;20&quot;&gt;set it to 20&lt;/button&gt;.&lt;/p&gt;
&lt;h3&gt;Progress&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;progress&amp;gt;&lt;/code&gt; element is intended for displaying the state of some process as it progresses from start to end,
like a loading or saving status indicator.&lt;/p&gt;
&lt;p&gt;However, it could also display a general &amp;quot;in progress&amp;quot; state when no parameter provided:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &amp;lt;progress max=&amp;quot;100&amp;quot;&amp;gt;&amp;lt;/progress&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;progress max=&quot;100&quot;&gt;&lt;/progress&gt;&lt;/p&gt;
&lt;p&gt;When it&#39;s more parameterized, it looks different:&lt;/p&gt;
&lt;div id=&quot;progress-demo&quot;&gt;&lt;/div&gt;
&lt;p&gt;(press &amp;quot;Reset&amp;quot; to put it back to 0).&lt;/p&gt;
&lt;h3&gt;SolidJS&lt;/h3&gt;
&lt;p&gt;And what about SolidJS? It proved to be a useful and simple way to add reactivity to the page - for example, meter part looks like this inside the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    import { createSignal } from &amp;quot;https://cdn.skypack.dev/solid-js&amp;quot;;
    import { render } from &amp;quot;https://cdn.skypack.dev/solid-js/web&amp;quot;;
    import html from &amp;quot;https://cdn.skypack.dev/solid-js/html&amp;quot;;

    const [metric, setMetric] = createSignal(20);

    const MeterApp = () =&amp;gt; {
    
        const metricFromEvent = (event) =&amp;gt; {
            setMetric(parseInt(event.target.value));
        };
    
        return html`
            &amp;lt;label for=&amp;quot;metric-input&amp;quot;&amp;gt;Metric value: &amp;lt;/label&amp;gt;
            &amp;lt;input type=&amp;quot;number&amp;quot; id=&amp;quot;metric-input&amp;quot; min=&amp;quot;0&amp;quot; max=&amp;quot;100&amp;quot; value=&amp;quot;${metric}&amp;quot; step=&amp;quot;1&amp;quot; onchange=&amp;quot;${metricFromEvent}&amp;quot;/&amp;gt;
            &amp;lt;br/&amp;gt;
            &amp;lt;meter value=&amp;quot;${metric}&amp;quot; min=&amp;quot;0&amp;quot; max=&amp;quot;100&amp;quot; low=&amp;quot;25&amp;quot; optimum=&amp;quot;50&amp;quot; high=&amp;quot;75&amp;quot; id=&amp;quot;metric-display&amp;quot; title=&amp;quot;Meter Demo&amp;quot;/&amp;gt;
        `;
    };
    render(MeterApp, document.getElementById(&amp;quot;meter-demo&amp;quot;));
&lt;/code&gt;&lt;/pre&gt;
&lt;style&gt;
meter, progress {
  width: 500px;
  height: 50px;
}
input, button {
    border: solid 1px grey;
    border-radius: 5px;
}
&lt;/style&gt;
&lt;script type=&quot;module&quot;&gt;
    import {
    createSignal,
    } from &quot;https://cdn.skypack.dev/solid-js&quot;;
    import { render } from &quot;https://cdn.skypack.dev/solid-js/web&quot;;
    import html from &quot;https://cdn.skypack.dev/solid-js/html&quot;;

    const [metric, setMetric] = createSignal(20);

    const MeterApp = () =&gt; {
    
        const metricFromEvent = (event) =&gt; {
            setMetric(parseInt(event.target.value));
        };
    
        return html`
            &lt;label for=&quot;metric-input&quot;&gt;Metric value: &lt;/label&gt;
            &lt;input type=&quot;number&quot; id=&quot;metric-input&quot; min=&quot;0&quot; max=&quot;100&quot; value=&quot;${metric}&quot; step=&quot;1&quot; onchange=&quot;${metricFromEvent}&quot;/&gt;
            &lt;br/&gt;
            &lt;meter value=&quot;${metric}&quot; min=&quot;0&quot; max=&quot;100&quot; low=&quot;25&quot; optimum=&quot;50&quot; high=&quot;75&quot; id=&quot;metric-display&quot; title=&quot;Meter Demo&quot;/&gt;
        `;
    };
    render(MeterApp, document.getElementById(&quot;meter-demo&quot;));

    const ProgressApp = () =&gt; {
        const [progress, setProgress] = createSignal(0);
    
        setInterval(() =&gt; {progress() &lt; 100 &amp;&amp; setProgress(progress() + 1)}, 500);        

        return html`
            &lt;p class=&quot;pre&quot;&gt;&amp;lt;progress value=&quot;${progress}&quot; max=&quot;100&quot; id=&quot;progress-display&quot;/&amp;gt;&lt;/p&gt;
            &lt;progress value=&quot;${progress}&quot; max=&quot;100&quot; id=&quot;progress-display&quot;/&gt;
            &lt;br/&gt;
            &lt;button onClick=${() =&gt; setProgress(0)}&gt;Reset&lt;/button&gt;
        `;
    };
    render(ProgressApp, document.getElementById(&quot;progress-demo&quot;));

    function metricClickSetter(event) {
        setMetric(event.target.value);
    }

    document.querySelectorAll(&#39;button.set-metric&#39;).forEach((item) =&gt; item.addEventListener(&#39;click&#39;, metricClickSetter));
&lt;/script&gt;
</content>
    </entry>
    
    <entry>
        <title>React Hook Testing Pass Reactive Variable To Hook</title>
        <link href="https://hydralien.net/blog//posts/react-hook-testing-pass-reactive-variable-to-hook/"/>
        <updated>2023-01-07T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/react-hook-testing-pass-reactive-variable-to-hook/</id>
        <content type="html">&lt;h4&gt;The Problem&lt;/h4&gt;
&lt;p&gt;I&#39;m still fairly new to React, and especially to the ways of testing it. So when I faced a hook that received a reactive variable
and did different things depending on its state, I was puzzled how to test it as useState cannot be called outside of React context.&lt;/p&gt;
&lt;p&gt;Additionally, due to some conditions I can&#39;t identify, tests were just hanging if I passed non-reactive variable - it might be
a combination of software versions or something else, as I couldn&#39;t replicate it in simplified environment.&lt;/p&gt;
&lt;h4&gt;The Solution&lt;/h4&gt;
&lt;p&gt;Obvious in retrospect, the &lt;code&gt;useState()&lt;/code&gt; could be called inside &lt;code&gt;renderHook&lt;/code&gt;! So the solution looked like&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    it(&#39;should return length&#39;, async () =&amp;gt; {
        const {result: hookResult, waitForNextUpdate} = renderHook(() =&amp;gt; {
            const [inputData, setInputData] = useState([&amp;quot;one&amp;quot;]);
            const hookResult = MyHook({inputValue: inputData});
            useEffect(() =&amp;gt; {
                setInputData([&amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;]);
            }, []);
            return hookResult;
        });

        await waitForNextUpdate();

        expect(hookResult.current.result).toEqual(2);
    })
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; &lt;code&gt;waitForNextUpdate&lt;/code&gt; is needed only if the component is expected to re-render, it might not be required.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Reacting On Page Button Click In SolidJS</title>
        <link href="https://hydralien.net/blog//posts/reacting-on-page-button-click-in-solidjs/"/>
        <updated>2023-01-07T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/reacting-on-page-button-click-in-solidjs/</id>
        <content type="html">&lt;h3&gt;What&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.solidjs.com/guides/getting-started&quot;&gt;SolidJS&lt;/a&gt; is a nice little reactive framework that allows to add reactivity to the page
without the need to have the whole page rendered by it. Not that it cannot be, but my use case was specifically that -
to add a dynamic element to a page without changing rendering engine or writing much raw JS.&lt;/p&gt;
&lt;p&gt;It all works nicely (example below), but I was confused how to change variable state when I click on buttons that are
not rendered by SolidJS - because I wanted to have most of the page in Markdown/HTML, as it&#39;s easier to manage.&lt;/p&gt;
&lt;p&gt;It could be done via assigning functions wo window object like e.g.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    window.myFunc = () =&amp;gt; {...}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;inside SolidJS code, and then call them from onclick() handler in button elements, but that would pollute the window namespace so not nice.&lt;/p&gt;
&lt;p&gt;Instead, there&#39;s a way to find all required DOM elements and add event listeners to them like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    function sliderClickSetter(event) {
        setSliderValue(event.target.value);
    }

    document.querySelectorAll(&#39;button.set-slider&#39;).forEach((item) =&amp;gt; item.addEventListener(&#39;click&#39;, sliderClickSetter));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here I select them by element type and style class (&lt;code&gt;button.set-slider&lt;/code&gt;) and use element&#39;s value,
but it could be ID selector as well (and &lt;code&gt;querySelector&lt;/code&gt; instead of &lt;code&gt;querySelectorAll&lt;/code&gt;, as it&#39;d return just one element).&lt;/p&gt;
&lt;h3&gt;Example&lt;/h3&gt;
&lt;h4&gt;Buttons in HTML code:&lt;/h4&gt;
&lt;div class=&quot;frame&quot;&gt;
    Set slider &lt;button class=&quot;set-slider&quot; value=&quot;90&quot;&gt;to 90&lt;/button&gt; or &lt;button class=&quot;set-slider&quot; value=&quot;20&quot;&gt;to 20&lt;/button&gt;
&lt;/div&gt;
&lt;h4&gt;Rendered by SolidJS:&lt;/h4&gt;
&lt;div class=&quot;frame&quot; id=&quot;slider-app&quot;&gt;&lt;/div&gt;&lt;br /&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;h4&gt;HTML part (without styles)&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;    &amp;lt;div class=&amp;quot;frame&amp;quot;&amp;gt;
        Set slider &amp;lt;button class=&amp;quot;set-slider&amp;quot; value=&amp;quot;90&amp;quot;&amp;gt;to 90&amp;lt;/button&amp;gt; or &amp;lt;button class=&amp;quot;set-slider&amp;quot; value=&amp;quot;20&amp;quot;&amp;gt;to 20&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
    
    &amp;lt;div class=&amp;quot;frame&amp;quot; id=&amp;quot;slider-app&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Javascript&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;    import { createSignal } from &amp;quot;https://cdn.skypack.dev/solid-js&amp;quot;;
    import { render } from &amp;quot;https://cdn.skypack.dev/solid-js/web&amp;quot;;
    import html from &amp;quot;https://cdn.skypack.dev/solid-js/html&amp;quot;;

    const [sliderValue, setSliderValue] = createSignal(50);

    const SliderApp = () =&amp;gt; {
    
        const valueFromEvent = (event) =&amp;gt; {
            setSliderValue(parseInt(event.target.value));
        };
    
        return html`
            &amp;lt;input type=&amp;quot;range&amp;quot; id=&amp;quot;slider&amp;quot; min=&amp;quot;0&amp;quot; max=&amp;quot;100&amp;quot; value=&amp;quot;${sliderValue}&amp;quot; onchange=&amp;quot;${valueFromEvent}&amp;quot;&amp;gt;
            &amp;lt;p&amp;gt;Slider value: &amp;lt;em&amp;gt;${sliderValue}&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
        `;
    };
    render(SliderApp, document.getElementById(&amp;quot;slider-app&amp;quot;));

    function sliderClickSetter(event) {
        setSliderValue(event.target.value);
    }

    document.querySelectorAll(&#39;button.set-slider&#39;).forEach((item) =&amp;gt; item.addEventListener(&#39;click&#39;, sliderClickSetter));
&lt;/code&gt;&lt;/pre&gt;
&lt;style&gt;
input, button {
    border: solid 1px grey;
    border-radius: 5px;
}
input[type=&quot;range&quot;] {
  width: 500px;
  height: 50px;
}
&lt;/style&gt;
&lt;script type=&quot;module&quot;&gt;
    import { createSignal } from &quot;https://cdn.skypack.dev/solid-js&quot;;
    import { render } from &quot;https://cdn.skypack.dev/solid-js/web&quot;;
    import html from &quot;https://cdn.skypack.dev/solid-js/html&quot;;

    const [sliderValue, setSliderValue] = createSignal(50);

    const SliderApp = () =&gt; {
    
        const valueFromEvent = (event) =&gt; {
            setSliderValue(parseInt(event.target.value));
        };
    
        return html`
            &lt;input type=&quot;range&quot; id=&quot;slider&quot; min=&quot;0&quot; max=&quot;100&quot; value=&quot;${sliderValue}&quot; onchange=&quot;${valueFromEvent}&quot;&gt;
            &lt;p&gt;Slider value: &lt;em&gt;${sliderValue}&lt;/em&gt;&lt;/p&gt;
        `;
    };
    render(SliderApp, document.getElementById(&quot;slider-app&quot;));

    function sliderClickSetter(event) {
        setSliderValue(event.target.value);
    }

    document.querySelectorAll(&#39;button.set-slider&#39;).forEach((item) =&gt; item.addEventListener(&#39;click&#39;, sliderClickSetter));
&lt;/script&gt;
</content>
    </entry>
    
    <entry>
        <title>React: Why Not To Use act() (In Most Of The Cases)</title>
        <link href="https://hydralien.net/blog//posts/react-why-not-to-use-act/"/>
        <updated>2023-01-08T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/react-why-not-to-use-act/</id>
        <content type="html">&lt;h4&gt;The Problem&lt;/h4&gt;
&lt;p&gt;As someone new to the React and its testing, I was reviewing some tests we have and (perhaps obviously) noticed a lot of usage of &lt;a href=&quot;https://reactjs.org/docs/test-utils.html#act&quot;&gt;act()&lt;/a&gt; function.&lt;/p&gt;
&lt;p&gt;And so I went along with it until I found a construct that looked suspiciously excessive:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    await act(async () =&amp;gt; {
        render(&amp;lt;App /&amp;gt;);
    });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I simplify it here, but the gist is wrapping component in async function inside act().&lt;/p&gt;
&lt;p&gt;So I started to digging for why to we need act at all, and turned out that in most cases we &lt;strong&gt;actually don&#39;t need it&lt;/strong&gt;.
There&#39;s a very good article about it, &amp;quot;&lt;a href=&quot;https://javascript.plainenglish.io/you-probably-dont-need-act-in-your-react-tests-2a0bcd2ad65c&quot;&gt;You Probably Don’t Need act() in Your React Tests&lt;/a&gt;&amp;quot; -
it explains what act() does, and turns out most of the functions provided by &lt;a href=&quot;https://testing-library.com/docs/react-testing-library/intro/&quot;&gt;React testing library&lt;/a&gt;
are already doing what act() does - so things like &lt;code&gt;render&lt;/code&gt;, &lt;code&gt;userEven&lt;/code&gt;, &lt;code&gt;fireEvent&lt;/code&gt; &lt;strong&gt;already wrap the code in act()&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The code mentioned above tries to cope with &lt;code&gt;An update to App inside a test was not wrapped in act(...)&lt;/code&gt; error, which
happens due to asynchronous code running in component and being executed in event loop &lt;em&gt;after the test code&lt;/em&gt;.
So wrapping it in async &lt;em&gt;looks like&lt;/em&gt; it solves the problem, but it really doesn&#39;t.&lt;/p&gt;
&lt;p&gt;From the aforementioned article, the solution above is equivalent to&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    render(&amp;lt;App /&amp;gt;);
    await act(async () =&amp;gt; {});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and only works because new await() happens in the next tick of the event loop.&lt;/p&gt;
&lt;h4&gt;The solution&lt;/h4&gt;
&lt;p&gt;The right way to address this would be to use either &lt;a href=&quot;https://testing-library.com/docs/dom-testing-library/api-async/#waitfor&quot;&gt;waitFor&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    await waitFor(() =&amp;gt; expect(screen.getByText(&amp;quot;something&amp;quot;)).toBeInTheDocument());
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or the &lt;a href=&quot;https://testing-library.com/docs/dom-testing-library/api-async/#findby-queries&quot;&gt;async variants&lt;/a&gt; of search in rendered document, e.g.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    expect(await screen.findByText(&amp;quot;something&amp;quot;)).toBeInTheDocument();
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;When to use act()&lt;/h4&gt;
&lt;p&gt;There are certainly still cases where act() might be needed, &lt;a href=&quot;https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning#other-use-cases-for-manually-calling-act&quot;&gt;here&#39;s a large collection&lt;/a&gt; that I&#39;m yet to go through -
though at least some cases (related to hooks) could be handled by &lt;a href=&quot;https://react-hooks-testing-library.com/reference/api#renderhook&quot;&gt;renderHook&lt;/a&gt; and the waitForNextUpdate that it returns.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPD&lt;/strong&gt;: A short overview of the use cases for the act(): &lt;a href=&quot;https://hydralien.net/blog/posts/react-when-to-use-act/&quot;&gt;https://hydralien.net/blog/posts/react-when-to-use-act/&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Add Svelte App To 11ty Page With Help From ChatGPT</title>
        <link href="https://hydralien.net/blog//posts/add-svelte-app-to-11ty-page-with-chat-gpt/"/>
        <updated>2023-02-26T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/add-svelte-app-to-11ty-page-with-chat-gpt/</id>
        <content type="html">&lt;h4&gt;The Goal&lt;/h4&gt;
&lt;p&gt;When I was writing the &lt;a href=&quot;https://hydralien.net/blog/posts/meter-and-progress-html-elements-with-solidjs/&quot;&gt;article about Meter And Progress HTML Elements&lt;/a&gt;,
I wanted to make it interactive and so to use some simple reactive JS framework for it - originally I thought of Svelte because I haven&#39;t really used it before,
but when I tried to turn one blog page into a &lt;a href=&quot;https://svelte.dev/&quot;&gt;Svelte&lt;/a&gt; app it didn&#39;t look promising - I thought I&#39;d need to redefine the renderer for one page somehow
(the blog is in Markdown), so I ended up juts loading &lt;a href=&quot;https://www.solidjs.com/&quot;&gt;SolidJS&lt;/a&gt; by CDN URL and using it on the page.&lt;/p&gt;
&lt;p&gt;I kinda still wanted to try Svelte so I thought that&#39;d make an interesting exercise of trying &lt;a href=&quot;https://chat.openai.com/&quot;&gt;ChatGPT&lt;/a&gt; - because I wanted to try it
and I couldn&#39;t come up with anything reasonably relevant.&lt;/p&gt;
&lt;h4&gt;Look Ma No Hands!&lt;/h4&gt;
&lt;p&gt;And so I went asking ChatGPT for how to do it - first how to create a Svelte app, by asking &amp;quot;&lt;em&gt;How to create simple Svelte app&lt;/em&gt;&amp;quot;, and then &amp;quot;&lt;em&gt;Show me simple Svelte app please&lt;/em&gt;&amp;quot;.&lt;/p&gt;
&lt;p&gt;Interestingly enough, first request only gave some command-line suggestions on how to scaffold the app, and second provided actual example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &amp;lt;script&amp;gt;
      let count = 0;
      
      function increment() {
        count += 1;
      }
      
      function decrement() {
        count -= 1;
      }
    &amp;lt;/script&amp;gt;
    
    &amp;lt;button on:click={increment}&amp;gt;+1&amp;lt;/button&amp;gt;
    &amp;lt;span&amp;gt;{count}&amp;lt;/span&amp;gt;
    &amp;lt;button on:click={decrement}&amp;gt;-1&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    &amp;lt;script&amp;gt;
      import Counter from &#39;./Counter.svelte&#39;;
    &amp;lt;/script&amp;gt;
    
    &amp;lt;Counter /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which resembles Svelte tutorial examples from &lt;a href=&quot;https://svelte.dev/examples/reactive-assignments&quot;&gt;https://svelte.dev/examples/reactive-assignments&lt;/a&gt;
as well as sample app created by &lt;code&gt;npm init vite&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And that&#39;s good, however the problem was that scaffolding instructions ChatGPT suggested were all outdated - &lt;code&gt;svelte create my-app&lt;/code&gt; doesn&#39;t work,
and neither does &lt;code&gt;npx degit sveltejs/template my-svelte-app&lt;/code&gt; - however when googling for the latter, it mentions to use &lt;code&gt;npm init vite&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then to find a solution to  the problem of adding Svelte app t 11ty, I formulated it as &amp;quot;&lt;em&gt;how to add Svelte app to 11ty page&lt;/em&gt;&amp;quot;.
It suggested yet another obsolete scaffolding mechanism, &lt;code&gt;npx create-svelte-app my-svelte-app&lt;/code&gt; - it didn&#39;t work, but I already help &lt;a href=&quot;https://vitejs.dev/&quot;&gt;ViteJS&lt;/a&gt;-based app operational.&lt;/p&gt;
&lt;p&gt;The instructions to add the app to the page were also not entirely correct:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Create your Svelte app: You can create a new Svelte app using a tool like create-svelte-app, or you can use an existing Svelte app.&lt;/li&gt;
&lt;li&gt;Build your Svelte app: Once you have created your Svelte app, you need to build it. Run npm run build in your Svelte app directory to build your app. This will create a public/build directory containing your app&#39;s JavaScript and CSS files.&lt;/li&gt;
&lt;li&gt;Add Svelte files to 11ty project: Copy the Svelte public/build files into your 11ty project directory.&lt;/li&gt;
&lt;li&gt;Include Svelte files in 11ty template: In the 11ty template where you want to include your Svelte app, you can include the Svelte JavaScript and CSS files that you copied in step 3.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;    &amp;lt;!-- Example 11ty template --&amp;gt;
    &amp;lt;!DOCTYPE html&amp;gt;
    &amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;
      &amp;lt;head&amp;gt;
        &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot; /&amp;gt;
        &amp;lt;title&amp;gt;My 11ty Page&amp;lt;/title&amp;gt;
        &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;/path/to/svelte-app.css&amp;quot; /&amp;gt;
      &amp;lt;/head&amp;gt;
      &amp;lt;body&amp;gt;
        &amp;lt;div id=&amp;quot;svelte-app&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;script src=&amp;quot;/path/to/svelte-app.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
      &amp;lt;/body&amp;gt;
    &amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;In the example above, the link tag references the CSS file generated by your Svelte app, and the script tag references the JavaScript file generated by your Svelte app.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Initialize Svelte app: Finally, you need to initialize your Svelte app by adding the following code to your JavaScript file:&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;    import App from &#39;./App.svelte&#39;;
    
    const app = new App({
        target: document.getElementById(&#39;svelte-app&#39;)
    });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which is a mix of a correct instructions (building an app and copying build files and adding them to a page) and incorrect ones (importing the App.svelte is already a part of a compiled code).&lt;/p&gt;
&lt;h4&gt;All In All&lt;/h4&gt;
&lt;p&gt;In the end, the information direction is legit - make an app, build an app, add build to the page (kinda the same as with a pre-built framework, but the whole app instead).
But it&#39;s not really reliable - which I actually wasn&#39;t expecting it to be, but to outline the impression: it&#39;s a nice toy,
and I imagine the less precise tasks (like writing a CV or any sort of generic text) would yield a better result,
but any strict factual requests are not usable - or not immediately usable, anyway.&lt;/p&gt;
&lt;p&gt;So as a result, here&#39;s the sample Svelte app - not doing much, but it&#39;s working:&lt;/p&gt;
&lt;div id=&quot;svelte-app&quot; class=&quot;frame&quot;&gt;&lt;/div&gt;
&lt;script src=&quot;https://hydralien.net/blog/assets/svelte-app.js&quot; lang=&quot;js&quot;&gt;&lt;/script&gt;
&lt;style&gt;
    #svelte-app {
        back
    }
&lt;/style&gt;
&lt;h4&gt;Liar Liar Pants On Fire&lt;/h4&gt;
&lt;p&gt;As a bit of fun, I also tried asking a lesser known but still fairly strictly factual information, such as &amp;quot;&lt;em&gt;Who founded Moscow State University?&lt;/em&gt;&amp;quot;,
to which I received a bunch of pleasantly delivered nonsense:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Moscow State University was founded by Prince Nikolay Ivanovich Lobachevsky and Count Sergey Semenovich Uvarov in 1755. The university is one of the oldest and largest universities in Russia and has a rich history of scientific and academic excellence.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Of which the real thing is only a founding year (and, well, &amp;quot;one of the oldest and largest&amp;quot; part). Which is OK because
the way the prediction model works does not promise any correct information - but to emphasise the importance to take it for it is.&lt;/p&gt;
&lt;p&gt;The results of &amp;quot;&lt;em&gt;Tell me a fairy tale about a red bug on a shiny platypus in a blue forest of death&lt;/em&gt;&amp;quot; were pretty satisfactory though ;)&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Full Page Screenshot In Google Chrome (With Inner Scroll)</title>
        <link href="https://hydralien.net/blog//posts/google-chrome-whole-page-screenshot/"/>
        <updated>2023-02-27T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/google-chrome-whole-page-screenshot/</id>
        <content type="html">&lt;h4&gt;Usually&lt;/h4&gt;
&lt;p&gt;How to make a full-page screenshot (if the page doesn&#39;t fit the screen) in Chrome is a fairly known (or at least easily google-able) trick:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;With the web page open, press &lt;span class=&quot;keyboard-shortcut&quot;&gt;&lt;em&gt;⌘&lt;/em&gt;⌥&lt;em&gt;I&lt;/em&gt;&lt;/span&gt; to launch Developer Tools (Shortcuts are for Mac; Windows shortcuts could be googled accordingly, I can&#39;t validate them unfortunately).&lt;/li&gt;
&lt;li&gt;Then, press &lt;span class=&quot;keyboard-shortcut&quot;&gt;&lt;em&gt;⌘&lt;/em&gt;⇧&lt;em&gt;P&lt;/em&gt;&lt;/span&gt;, or select &amp;quot;&lt;em&gt;Run Command&lt;/em&gt;&amp;quot; item in the menu:&lt;/li&gt;
&lt;/ul&gt;
&lt;img src=&quot;https://hydralien.net/blog/assets/screenshots/run-command-menu.png&quot; alt=&quot;Run Command&quot; style=&quot;max-width: 90%&quot; /&gt;
&lt;ul&gt;
&lt;li&gt;In the search bar, type &amp;quot;screenshot&amp;quot;, and select &amp;quot;&lt;em&gt;Capture full size screenshot&lt;/em&gt;&amp;quot;, and Chrome will automatically save a full-page screenshot to your Downloads folder.&lt;/li&gt;
&lt;/ul&gt;
&lt;img src=&quot;https://hydralien.net/blog/assets/screenshots/full-size-screenshot.png&quot; alt=&quot;Full Size Screenshot&quot; style=&quot;max-width: 90%&quot; /&gt;
&lt;h4&gt;Less Usually&lt;/h4&gt;
&lt;p&gt;The issue arises when the content is in a container within a page - so the whole page is not really larger than browser&#39;s viewpoint,
but the content is still large and is scrollable within a component - like in the case of &lt;a href=&quot;https://chat.openai.com/&quot;&gt;ChatGPT&lt;/a&gt; answers.&lt;/p&gt;
&lt;p&gt;In such case, you need to open the Developer Tools, and find the component that holds the scrollable part. It might be tricky,
but usually using the picker (arrow button on top-left of the console, or &lt;span class=&quot;keyboard-shortcut&quot;&gt;&lt;em&gt;⌘&lt;/em&gt;⇧&lt;em&gt;C&lt;/em&gt;&lt;/span&gt; combination) helps with that.&lt;/p&gt;
&lt;p&gt;Then, make sure you set a large &lt;em&gt;height&lt;/em&gt; (or &lt;em&gt;width&lt;/em&gt;, if that&#39;s the case) for the element (e.g. &lt;em&gt;1000%&lt;/em&gt;),
and that it&#39;s &amp;quot;&lt;em&gt;overflow&lt;/em&gt;&amp;quot; setting is disabled (or set to &amp;quot;&lt;em&gt;visible&lt;/em&gt;&amp;quot;) - here&#39;s the ChatGPT case:&lt;/p&gt;
&lt;img src=&quot;https://hydralien.net/blog/assets/screenshots/set-height.png&quot; alt=&quot;Set Height&quot; style=&quot;max-width: 90%&quot; /&gt;
&lt;p&gt;Once done, follow the screenshot-taking sequence mentioned above.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Passing Moment, Or Moment.js Replacement</title>
        <link href="https://hydralien.net/blog//posts/passing-moment-or-moment-js-replacement/"/>
        <updated>2023-03-04T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/passing-moment-or-moment-js-replacement/</id>
        <content type="html">&lt;h4&gt;The problem&lt;/h4&gt;
&lt;p&gt;At some point while dealing with date/time in JS code and searching for some clues, I stumbled over an advice &amp;quot;just use Moment&amp;quot; -
and at that time, it was quite revelatory - I wasn&#39;t much used to the npm &amp;quot;package for everything&amp;quot; attitude, and haven&#39;t really thought
that so many problems could have been solved by just using the right library.&lt;/p&gt;
&lt;p&gt;And &lt;a href=&quot;https://momentjs.com/&quot;&gt;Moment.js&lt;/a&gt; stuck with me ever since - not that I needed day/time parsing or manipulation every day,
but when I did need it, the answer was clear - just use Moment!&lt;/p&gt;
&lt;p&gt;So it was quite a surprise to me that it&#39;s being deprecated - in fact, has been for quite some time already. The obvious questions
were &amp;quot;&lt;em&gt;why?&lt;/em&gt;&amp;quot; and &amp;quot;&lt;em&gt;what now?&lt;/em&gt;&amp;quot;.&lt;/p&gt;
&lt;h4&gt;Why?&lt;/h4&gt;
&lt;p&gt;Apparently Model.js has aged and doesn&#39;t do as good a job as it did before - as the maintainers say at the https://momentjs.com/docs/#/-project-status/future/,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Moment was built for the previous era of the JavaScript ecosystem. The modern web looks much different these days.
Moment has evolved somewhat over the years, but it has essentially the same design as it did when it was created in 2011.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Some of the problems one could fin on the Web is slowness, large size, mutability and debugging problems. For instance,
there&#39;s a good comparison of the Moment against other libraries (and native solution) at &lt;a href=&quot;https://inventi.studio/en/blog/why-you-shouldnt-use-moment-js&quot;&gt;https://inventi.studio/en/blog/why-you-shouldnt-use-moment-js&lt;/a&gt; -
it&#39;s actually from pre-deprecation times, but I&#39;d expect it still holds true:&lt;/p&gt;
&lt;img src=&quot;https://res.cloudinary.com/dmhd8lsl2/image/upload/v1677929690/hydralien.net/datetime-libraries-performance_zifsir.png&quot; alt=&quot;Moment.js performance comparison&quot; style=&quot;max-width: 90%&quot; /&gt;
&lt;h4&gt;What now?&lt;/h4&gt;
&lt;p&gt;There&#39;s a &amp;quot;recommendations&amp;quot; section on the Moment&#39;s website itself: &lt;a href=&quot;https://momentjs.com/docs/#/-project-status/recommendations/&quot;&gt;https://momentjs.com/docs/#/-project-status/recommendations/&lt;/a&gt;,
which list several alternatives, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://moment.github.io/luxon/&quot;&gt;Luxon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://day.js.org/&quot;&gt;Day.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://date-fns.org/&quot;&gt;date-fns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://js-joda.github.io/js-joda/&quot;&gt;js-Joda&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&#39;s almost too much choice, but luckily that &lt;a href=&quot;https://inventi.studio/en/blog/why-you-shouldnt-use-moment-js&quot;&gt;pre-deprecation article&lt;/a&gt;
I&#39;ve mentioned earlier has als a comparison of these alternatives considering certain functionality and size:&lt;/p&gt;
&lt;img src=&quot;https://res.cloudinary.com/dmhd8lsl2/image/upload/v1677929690/hydralien.net/datetime-libraries-comparison_umkdlg.png&quot; alt=&quot;Date/time libraries comparison&quot; style=&quot;max-width: 90%&quot; /&gt;
&lt;p&gt;Which (among some suggestions elsewhere) points out that for general cases, &lt;a href=&quot;https://day.js.org/&quot;&gt;Day.js&lt;/a&gt; or &lt;a href=&quot;https://date-fns.org/&quot;&gt;date-fns&lt;/a&gt;
are probably the best choice, while for tricky cases and error-prone data &lt;a href=&quot;https://moment.github.io/luxon/&quot;&gt;Luxon&lt;/a&gt; might be a better choice.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>React: When To Use act()</title>
        <link href="https://hydralien.net/blog//posts/react-when-to-use-act/"/>
        <updated>2023-03-04T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/react-when-to-use-act/</id>
        <content type="html">&lt;h4&gt;Long story short&lt;/h4&gt;
&lt;p&gt;In another article before (&lt;a href=&quot;https://hydralien.net/blog/posts/react-why-not-to-use-act/&quot;&gt;React: Why Not To Use act() (In Most Of The Cases)&lt;/a&gt;),
I&#39;ve outlined why the act() is probably not something one should use when faced with a &amp;quot;&lt;em&gt;not wrapped in act(...)&lt;/em&gt;&amp;quot; warning in tests using React Testing Library
(TL;DR most of the &lt;a href=&quot;https://testing-library.com/docs/react-testing-library/intro/&quot;&gt;React Testing Library&lt;/a&gt; functions are already wrapped in act() internally).&lt;/p&gt;
&lt;p&gt;But then, why does it exist and when to use it? There&#39;s a long and detailed article on the subject: &lt;a href=&quot;https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning#other-use-cases-for-manually-calling-act&quot;&gt;https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning#other-use-cases-for-manually-calling-act&lt;/a&gt;
but in short, when the status update in the code executed asynchronously is not going to be executed within React&#39;s callstack - for instance,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When using &lt;code&gt;jest.useFakeTimers()&lt;/code&gt; to manipulate the timers and timer-controlled functionality, so e.g. &lt;code&gt;jest.advanceTimersByTime(1000)&lt;/code&gt; should be called as &lt;code&gt;act(() =&amp;gt; jest.advanceTimersByTime(1000))&lt;/code&gt; (there&#39;s a detailed example in the aforementioned article).&lt;/li&gt;
&lt;li&gt;When testing custom hooks: if a hook returns a function that could manage a state later, its call might need to be wrapped in act() as &lt;code&gt;act(() =&amp;gt; result.current.functionThatSetsState())&lt;/code&gt; for the &lt;code&gt;const {result} = renderHook(() =&amp;gt; useHookThatReturnsStaetSetterFunction())&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;When using &lt;code&gt;useImperativeHandle&lt;/code&gt; hook - I&#39;m not familiar with it, but to quote the article, &amp;quot;&lt;em&gt;you only run into this if you&#39;re calling methods directly on a component which do internal state updates and you&#39;re outside of React&#39;s callstack&lt;/em&gt;&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <title>On Conducting Technical Interviews</title>
        <link href="https://hydralien.net/blog//posts/on-conducting-technical-interviews/"/>
        <updated>2023-03-05T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/on-conducting-technical-interviews/</id>
        <content type="html">&lt;h4&gt;Yet Another Opinion&lt;/h4&gt;
&lt;p&gt;I&#39;ve recently started conducting technical part of the software developer interviews again (I did quite a bit of it before
as IPONWEB and Booking.com), and thought I&#39;d summarize some thoughts and ideas on how it works best for me,
from the interviewer&#39;s side - but also from the candidate&#39;s side, too - as I&#39;ve been on that side a lot last year,
I have a fairly solid opinion on that too.&lt;/p&gt;
&lt;h4&gt;Being real&lt;/h4&gt;
&lt;p&gt;What I think works best for both sides is being real in the choice of assignment and questions about the results -
meaning, solving problems and using techniques that would apply to a real day-to-day job. It&#39;s best when it could relate
to what company does - e.g. if company builds an online email platform, a question about how to structure and store and search
through email tags/categories is very relevant. But it doesn&#39;t have to be that specific - any sort of realistic hands-on
task is good, as long as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it doesn&#39;t hinge on specific language quirks, like e.g. using &lt;code&gt;this&lt;/code&gt; in function vs arrow function;&lt;/li&gt;
&lt;li&gt;it doesn&#39;t imply just one correct solution (there might be a limited set of ways to do it optimally, but there shouldn&#39;t be only one way to do it);&lt;/li&gt;
&lt;li&gt;it&#39;s not an algorithmic puzzle of &amp;quot;you either know it or you don&#39;t&amp;quot; kind;&lt;/li&gt;
&lt;li&gt;it doesn&#39;t heavily relies on candidate following any by-the-book principles such as &lt;a href=&quot;https://en.wikipedia.org/wiki/SOLID&quot;&gt;SOLID&lt;/a&gt; or any other.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think there&#39;s many real-world scenarios that could lead to a discussion of efficient algorithms, data structures,
coding practices, design principles, collaboration and so on and so forth - but it needs ho be realistic, it needs to be relevant.&lt;/p&gt;
&lt;h4&gt;The way I like it&lt;/h4&gt;
&lt;p&gt;The interview flow I enjoyed as a candidate - and I try to employ as an interviewer - looks (roughly) like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Starting with a simple hands-on task, like parsing a CSV data or reading structured data from a source or aggregating provided data -
for the interviewer, it provides a way to estimate the communication detail level required for the interview, the pace,
maybe some areas where candidate might require hints; for the candidate, it&#39;s a simple and focused start without a need to understand the
large scope and a chance to shake an anxiety and get into the flow.&lt;/li&gt;
&lt;li&gt;Once initial scaffolding is done, expand the requirements to process the data or introduce additional variables to the system - e.g. for
the data parsing task, it could be calculating total amounts per column and ordering it, or extracting unique values. This stage
could be iterated several times over, adding extra columns to the data processing (ordering by several columns is a good exercise),
or adding several steps to data processing/filtering/transformation. It provides an understanding on how well candidate build on
the foundation, how they expand the problem perception and if they can keep up with changing complexity - and also if their solution
is flexible enough to accommodate new requirements, their coding style is readable, they can modularise the code to make it
reusable and understandable and so on. For the candidate, it&#39;s often the part with the most fun because it requires to really think
how to adjust and adapt and make it work, which closely resembles how things evolve in real-life projects.&lt;/li&gt;
&lt;li&gt;When enough iterations have passed and the solution provides sufficient insight in the candidate&#39;s skills, or the interview time
is running out, I find it useful to leave enough time to discuss the solution and potential improvement points, and also ask
the candidate why they used specific data structures or approach - it&#39;s nice to have a conversation, and it gives the candidate an
opportunity to express themselves and maybe explain things they&#39;ve struggled with or provide extra insight into how things should work.&lt;/li&gt;
&lt;li&gt;In the end, leaving some time for a free-form Q&amp;amp;A for teh candidate to ask any questions is also a useful part: they might want to learn
more about teh company and teh people they will potentially work with, and what questions they ask might also be a useful information.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;The unexpected&lt;/h4&gt;
&lt;p&gt;Sometimes, things don&#39;t go smooth, for various reasons. What&#39;s important is to provide the candidate enough space to think and try things,
but also to be there for them to answer any questions they have (and encourage to ask those questions), and to tot let them hanging - if
they&#39;re struggling, providing some hints or asking them to elaborate on whet they want to achieve is really helpful.
And just being polite and professional and compassionate - interviews are hard and stressful and exhausting, it&#39;s a MUCH harder work
for the candidate than for an interviewer.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>One Word At A Time, Or A Note About ChatGPT Principles</title>
        <link href="https://hydralien.net/blog//posts/one-word-at-a-time-or-chat-gpt-principles/"/>
        <updated>2023-03-14T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/one-word-at-a-time-or-chat-gpt-principles/</id>
        <content type="html">&lt;h4&gt;Hot topic&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://chat.openai.com/&quot;&gt;ChatGPT&lt;/a&gt; is indeed a hot topic nowadays - so when I shared a note about &lt;a href=&quot;https://www.salesforce.com/news/stories/chatgpt-app-for-slack/&quot;&gt;Slack jumping on ChatGPT bandwagon&lt;/a&gt; at the work chat,
a colleague recommended an article about why and how it works.&lt;/p&gt;
&lt;p&gt;I gave it an attempt (because it&#39;s &lt;strong&gt;A LOT&lt;/strong&gt;, for me at least) and even though I honestly skipped through a large part of it,
I think it&#39;s still a worthy read - even if just those parts that still make some sense.&lt;/p&gt;
&lt;h4&gt;Hard Things Simple (Or Not)&lt;/h4&gt;
&lt;p&gt;So the article itself is here: &lt;a href=&quot;https://writings.stephenwolfram.com/2023/02/what-is-chatgpt-doing-and-why-does-it-work/&quot;&gt;https://writings.stephenwolfram.com/2023/02/what-is-chatgpt-doing-and-why-does-it-work/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As I&#39;ve mentioned above, it&#39;s a lot - and I&#39;m not going to replicate any of it here. Instead, here&#39;s why I think it&#39;s worth reading
and how it could be consumed if it gets overwhelming at some point.&lt;/p&gt;
&lt;p&gt;It emphasises an important idea that (also as &lt;a href=&quot;https://hydralien.net/blog/posts/add-svelte-app-to-11ty-page-with-chat-gpt/&quot;&gt;my attempts to use it&lt;/a&gt; highlight)
it&#39;s not a search engine or knowledge base or anything that we humans might think it is given the results it produces.
Instead, it&#39;s a complex probabilistic model that selects what next word to put in the sentence based on probabilities
calculated from a very large amount of text it&#39;s been trained on.&lt;/p&gt;
&lt;p&gt;However, it&#39;s based on a &lt;a href=&quot;https://en.wikipedia.org/wiki/Neural_network&quot;&gt;neural networks&lt;/a&gt;, so it a way the mechanisms it&#39;s built upon
are trying to replicate how human brain works, so in certain sense it actually is based on what we humans might think it is.&lt;/p&gt;
&lt;h4&gt;Consumer&#39;s Guide&lt;/h4&gt;
&lt;p&gt;The article goes - at least for someone without any neural networks background, like myself - fairly deep into the theoretical part,
which at some point becomes overwhelming and incomprehensible.&lt;/p&gt;
&lt;p&gt;So I found it useful to start from the beginning and go as far as one&#39;s understanding of the text gets them, and when it becomes
too much skip to the last part of the article - roughly around &amp;quot;&lt;a href=&quot;https://writings.stephenwolfram.com/2023/02/what-is-chatgpt-doing-and-why-does-it-work/#:~:text=So%20%E2%80%A6%20What%20Is%20ChatGPT%20Doing%2C%20and%20Why%20Does%20It%20Work%3F&quot;&gt;So … What Is ChatGPT Doing, and Why Does It Work?&lt;/a&gt;&amp;quot; chapter.&lt;/p&gt;
&lt;p&gt;That last chapter provides ome important thought on the subjects - such as (just a few quotes):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;it’s just saying things that “sound right” based on what things “sounded like” in its training material.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;this suggests something that’s at least scientifically very important: that human language (and the patterns of thinking behind it) are somehow simpler and more “law like” in their structure than we thought.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and also&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;unlike even in typical algorithmic computation, ChatGPT doesn’t internally “have loops” or “recompute on data”. And that inevitably limits its computational capability—even with respect to current computers, but definitely with respect to the brain.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;The End&lt;/h4&gt;
&lt;p&gt;Even though it&#39;s easy to disregard the ChatGPT phenomena as &amp;quot;just a probabilistic model&amp;quot;, it&#39;s an impressive achievement that
is quite certainly a huge milestone in the development of the language processing, neural networks and the AI efforts.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Hitting The Books: An Impression Of The &quot;4000 Weeks&quot; Book</title>
        <link href="https://hydralien.net/blog//posts/4000-weeks-book-review/"/>
        <updated>2023-03-15T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/4000-weeks-book-review/</id>
        <content type="html">&lt;h4&gt;What Book?&lt;/h4&gt;
&lt;img src=&quot;https://m.media-amazon.com/images/W/IMAGERENDERING_521856-T1/images/I/81yI262BelL.jpg&quot; alt=&quot;4000 Weeks book cover&quot; style=&quot;max-width: 30%;&quot; /&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.oliverburkeman.com/books&quot;&gt;400 Weeks by Oliver Burkeman&lt;/a&gt; was one of the things recommended to me
by a friend when I asked for an advise on work/life situation and daily routines and focus and prioritisation of the daily tasks.&lt;/p&gt;
&lt;p&gt;I&#39;ve listened to it in an audiobook format - which might not have been the best medium for this book given the weight of the subject at hand,
but it was good enough as the narrator&#39;s voice and pace was great, and the book is written in a very voice-readable way:
it&#39;s easy to engage with, even given the fairly sobering subject that on average we have 4000 weeks of time in our lives.&lt;/p&gt;
&lt;p&gt;Overall it resonated with the core motive of &amp;quot;&lt;a href=&quot;https://markmanson.net/not-giving-a-fuck&quot;&gt;The Subtle Art of Not Giving a Fuck&lt;/a&gt;&amp;quot; by Mark Manson,
in a way that there&#39;s a limited amount of things we could attentively care about - and there&#39;s a limited amount of time we have
to care about things. So essentially the goal is to focus on what we really care about and spend our precious resources on things
that are dear to us, and not on amount of work we can do per day, or getting more efficient at time management - the latter, specifically, because if we
focus on getting work done more efficiently, there will just be more work to do, so instead it&#39;s more rewarding to focus on doing the
meaningful and rewarding work/activities/communication/relationships.&lt;/p&gt;
&lt;h4&gt;The Gist&lt;/h4&gt;
&lt;p&gt;It&#39;s well worth reading, and it&#39;s not a good idea for me to try to lay it out here - but what I wanted to save here for future
reference is some questions and hints found at the end of the book.&lt;/p&gt;
&lt;h5&gt;Questions...&lt;/h5&gt;
&lt;p&gt;...are things to ask yourself to decide how to choose and prioritise things in life:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Does this choice diminish or enlarge me? Choose uncomfortable enlargement over comfortable diminishment. &lt;em&gt;The &amp;quot;choice&amp;quot; being anything from work to friendship to relationships.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Impossible standards are impossible. Face it. Choose several achievable tasks and focus on those. &lt;em&gt;The &amp;quot;standards&amp;quot; being what we think we can do - or rather, what we thing we must do.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Nobody cares what we’re doing with our lives, so don’t struggle to prove it to anyone. How do you really enjoy spending your days? &lt;em&gt;We often have ingrained obligation to prove ourselves to parents, peers, society and so on - but nobody really needs that.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;In which areas are you waiting till you know what you’re doing? Nobody ever does, so don’t wait. &lt;em&gt;We want to be certain we have enough skills or knowledge or control to start doing something or pursuing an opportunity - but that&#39;s never sufficient, so no reason to wait.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;What actions might be meaningful today if you accept that you might never see the results? &lt;em&gt;There&#39;s certain fatalistic but liberating thought that we might never see the results of our efforts - but so what? What if we don&#39;t have to?&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Hints...&lt;/h5&gt;
&lt;p&gt;...are things that might help to get what answers to the questions above imply:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fixed volume approach to productivity: “eventual” todo list with everything, and “current” todo list win N tasks max, no adding new till some are done. Maybe one more for “blocked” things waiting on something.&lt;/li&gt;
&lt;li&gt;Focus on one or at most two projects at a time, till you’re done or it’s evidently not working.&lt;/li&gt;
&lt;li&gt;Accept that some things will have to be postponed/abandoned: work or sport when ill, renovation when changing jobs etc.&lt;/li&gt;
&lt;li&gt;Focus on things you did, not on what you need to do. Small wins are still wins, and they’re very encouraging.&lt;/li&gt;
&lt;li&gt;Limit and prioritize what you give a fuck about. &lt;a href=&quot;https://markmanson.net/not-giving-a-fuck&quot;&gt;There’s just so many fucks to give&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Make devices boring. Remove social media, for instance. Make the gadgets a tool, not an escape from your reality. &lt;em&gt;(I&#39;m leaving it here, though it sounds dubious to me; sounds like addressing the symptom rather than problem)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Embrace the mundane: everyday tasks could be engaging if you accept them as part of life they are and not as a burden.&lt;/li&gt;
&lt;li&gt;Curiosity over worry: instead of fearing what comes next or how tantalising the experience is going to be, be curious about what it actually is going to be and the process/conversation/surroundings. It most probably is going to be much better than you think.&lt;/li&gt;
&lt;li&gt;Be generous immediately: don’t delay giving a praise or make a donation or encourage someone.&lt;/li&gt;
&lt;li&gt;Learn to do nothing. Worry about nothing, just &lt;strong&gt;be&lt;/strong&gt; for a spell.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of the above is not a literal quote, rather my own impression/interpretation of the book&#39;s text - though I think it reflects the book&#39;s sentiments fairly well.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>On Conducting One-On-One Meetings</title>
        <link href="https://hydralien.net/blog//posts/on-conducting-one-on-one-meetings/"/>
        <updated>2023-03-18T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/on-conducting-one-on-one-meetings/</id>
        <content type="html">&lt;h4&gt;The Problem&lt;/h4&gt;
&lt;p&gt;There are various processes in the team day-to-day work that require personal communication - and communication is a hard thing to get right.
One of such communication types is one-on-one meetings (1x1, 1/1 and so on) - a format used to discuss personal matters, deliver (or ask for)
the feedback, discuss problems, establish growth direction and steps and so on.&lt;/p&gt;
&lt;h4&gt;1x1 or 1 vs 1?&lt;/h4&gt;
&lt;p&gt;When done right, it&#39;s a very useful part of the process - when communication is open and mutually respectful and responsive,
it really helps the personal and professional development, and especially to early detect and address any problems the individual might have.&lt;/p&gt;
&lt;p&gt;But when teh manager (or whoever is playing more senior role in the meeting) is not engaged or not interested or would rather be elsewhere,
it turns into an annoying chore and causes much harm as it makes the team member&#39;s distrust to the management, caging problems rather than discussing them,
and eventually making team a dysfunctional rather than efficient.&lt;/p&gt;
&lt;h4&gt;Expert opinion&lt;/h4&gt;
&lt;p&gt;There&#39;s a great article about the subject by my former Booking.com colleague:
&lt;a href=&quot;https://medium.com/@xsawyerx/perfectly-simple-and-simply-perfect-one-on-one-meetings-1a85cf695078&quot;&gt;https://medium.com/@xsawyerx/perfectly-simple-and-simply-perfect-one-on-one-meetings-1a85cf695078&lt;/a&gt; -
he has a lot more experience with it than I do, also from the managerial point of view - and I totally agree with what he has to say about the subject.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Typescript Export Was Not Found Error</title>
        <link href="https://hydralien.net/blog//posts/typescript-export-not-found-error/"/>
        <updated>2023-03-19T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/typescript-export-not-found-error/</id>
        <content type="html">&lt;h4&gt;The Problem&lt;/h4&gt;
&lt;p&gt;I recently encountered a fairly obscure error in a Typescript project, where I was exporting a type (via &lt;code&gt;export type TypeName ...&lt;/code&gt;),
and then importing it in another place with &lt;code&gt;import {TypeName} from ...&lt;/code&gt; - and when running the project (it was actually a package),
I encountered a strange error that TypeName was not found in the file where it was defined. It seemed very strange.&lt;/p&gt;
&lt;h4&gt;The solution&lt;/h4&gt;
&lt;p&gt;The way to solve it is to do &lt;code&gt;import type {TypeName} from ...&lt;/code&gt; - note the &amp;quot;&lt;strong&gt;type&lt;/strong&gt;&amp;quot; part. That&#39;s pretty much what was required.&lt;/p&gt;
&lt;h4&gt;But why?&lt;/h4&gt;
&lt;p&gt;There&#39;s a great article that explains the problem in understandable details:
&lt;a href=&quot;https://javascript.plainenglish.io/leveraging-type-only-imports-and-exports-with-typescript-3-8-5c1be8bd17fb&quot;&gt;https://javascript.plainenglish.io/leveraging-type-only-imports-and-exports-with-typescript-3-8-5c1be8bd17fb&lt;/a&gt;
but in short, types are not saved in transpiled code, but import can&#39;t always identify it&#39;s a type so the import might
remain in place - so when transpiled code tries to import the type, it&#39;s not available because types are removed when transpiling the code.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;import type&lt;/code&gt; directive tells transpiler that the type is imported, so it will be removed from the transpiled code as well
and the code will not try to look for it - more details at
&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export&quot;&gt;https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Importing SVG Files In Typescript React Project</title>
        <link href="https://hydralien.net/blog//posts/importing-svg-files-in-react-typescript/"/>
        <updated>2023-03-26T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/importing-svg-files-in-react-typescript/</id>
        <content type="html">&lt;h4&gt;Howto&lt;/h4&gt;
&lt;p&gt;To display SVG files on the page (as e.g. icons or images or other elements), there are several ways depending on circumstances and requirements.
For this case, I&#39;m mostly concerned with React project written in Typescript - though for JS (and non-React) projects some of the below options apply as well.&lt;/p&gt;
&lt;p&gt;Perhaps the simplest way is to just add it to the component &amp;quot;as is&amp;quot; - because it&#39;s a valid markup, things like&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    export const ComponentWithSvg = () =&amp;gt; (
        &amp;lt;div&amp;gt;
            &amp;lt;svg version=&amp;quot;1.1&amp;quot; id=&amp;quot;Layer_1&amp;quot; xmlns=&amp;quot;http://www.w3.org/2000/svg&amp;quot; xmlns:xlink=&amp;quot;http://www.w3.org/1999/xlink&amp;quot; x=&amp;quot;0px&amp;quot; y=&amp;quot;0px&amp;quot; width=&amp;quot;120px&amp;quot; height=&amp;quot;120px&amp;quot; viewBox=&amp;quot;0 0 120 120&amp;quot; enable-background=&amp;quot;new 0 0 120 120&amp;quot; xml:space=&amp;quot;preserve&amp;quot;&amp;gt;
                &amp;lt;path d=&amp;quot;M60,19.089C22.382,19.089,0.053,60,0.053,60S22.382,100.91,60,100.91S119.947,60,119.947,60S97.618,19.089,60,19.089z M59.999,84.409C46.54,84.409,35.59,73.459,35.59,60c0-13.459,10.95-24.409,24.409-24.409c13.459,0,24.409,10.95,24.409,24.409 C84.408,73.459,73.458,84.409,59.999,84.409z&amp;quot;/&amp;gt;
                &amp;lt;circle cx=&amp;quot;60&amp;quot; cy=&amp;quot;60.583&amp;quot; r=&amp;quot;14.409&amp;quot;/&amp;gt;
            &amp;lt;/svg&amp;gt;
        &amp;lt;/div&amp;gt;
    );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;would do just fine. Not reusable, not structured, not viewable independently - but it&#39;d work.&lt;/p&gt;
&lt;p&gt;If the project was created with &lt;a href=&quot;https://create-react-app.dev/&quot;&gt;Create React App&lt;/a&gt; or uses &lt;a href=&quot;https://parceljs.org/&quot;&gt;Parcel v2&lt;/a&gt; or was appropriately configured
to process assets automatically, another option is to import it like e.g.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    import iconPath from &#39;./iconFile.svg&#39;;

    export const ComponentWithSvg = () =&amp;gt; (
        &amp;lt;&amp;gt;
            &amp;lt;img src={iconPath}/&amp;gt;
        &amp;lt;/&amp;gt;
    );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or in case that imports file data as string, it should be possible to use it as a variable inside the component as e.g.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    import icon from &#39;./iconFile.svg&#39;;

    export const ComponentWithSvg = () =&amp;gt; (
        &amp;lt;&amp;gt;
            {icon}
        &amp;lt;/&amp;gt;
    );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&#39;s also an option to turn the icon into a ReactComponent and use it as such - though a bit more work, I think it&#39;s the
most structurally sound way:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add type declaration for the .svg files by creating &lt;code&gt;./src/@types/assets/index.d.ts&lt;/code&gt; file with content:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; declare module &amp;quot;&#92;*.svg&amp;quot; {
     import React = require(&amp;quot;react&amp;quot;);
     const ReactComponent: React.FC&amp;lt;React.SVGProps&amp;lt;SVGSVGElement&amp;gt;&amp;gt;;
     export default ReactComponent;
 }    
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In &lt;code&gt;tsconfig.json&lt;/code&gt;, configure typeRoots parameter to include the types:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; {
     ...
     &amp;quot;typeRoots&amp;quot;: [&amp;quot;./src/@types&amp;quot;, &amp;quot;./node_modules/@types&amp;quot;],
     ...
 }
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Import and use it as a component:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; import React from &amp;quot;react&amp;quot;;
 import { ReactComponent as SVGIcon } from &amp;quot;./icon.svg&amp;quot;;

 export const ComponentWithSvg = () =&amp;gt; (
     &amp;lt;&amp;gt;
         &amp;lt;SVGIcon /&amp;gt;
     &amp;lt;/&amp;gt;
 );
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content>
    </entry>
    
    <entry>
        <title>React: Using CSS Module Stylesheets</title>
        <link href="https://hydralien.net/blog//posts/react-css-module-stylesheets/"/>
        <updated>2023-05-02T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/react-css-module-stylesheets/</id>
        <content type="html">&lt;h4&gt;What Module CSS&lt;/h4&gt;
&lt;p&gt;Back when I was working on certain Vue.js projects, the styling came bundled with Vue modules, and was either inherently
bound to the module (i.e. in the same file as markup and code), or modularised but still coupled with the markup.&lt;/p&gt;
&lt;p&gt;The result was, styles were local to thw component by default (well, &amp;quot;by default&amp;quot; being mostly a scaffolding defaults, but still),
so style classes were automatically getting unique names via adding unique identified to the DOM element and changing style classes from e.g.
&lt;code&gt;.example&lt;/code&gt; into &lt;code&gt;.example[data-v-f3f3eg9]&lt;/code&gt; - so getting a common style actually required some work and consideration.&lt;/p&gt;
&lt;p&gt;React is more &amp;quot;manual&amp;quot; in this regard - a lot of code I&#39;ve seen just includes the CSS (or SCSS) like&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import * from ./styles.css
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then using &lt;code&gt;className=&amp;quot;MyClassName&amp;quot;&lt;/code&gt; classes in elements.&lt;/p&gt;
&lt;p&gt;Which is OK, but it often covers much more ground than needed - so if I&#39;m dealing with several similar components on the page
that need different styling (like if the component comes from a package that is used in several sub-components independently),
we got ourselves a problem, as whoever defined the styling for the class last, reigns supreme.&lt;/p&gt;
&lt;h4&gt;And so&lt;/h4&gt;
&lt;p&gt;There&#39;s a way to do things similar to Vue approach: &lt;a href=&quot;https://create-react-app.dev/docs/adding-a-css-modules-stylesheet/&quot;&gt;https://create-react-app.dev/docs/adding-a-css-modules-stylesheet/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Essentially, it&#39;s a way to make CSS class names unique per component instance, so each would have independent styles.
To re-use examples found in React docs, let&#39;s say we have styles in &lt;code&gt;Styles.module.css&lt;/code&gt;, and component in &lt;code&gt;Component.js&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.error {
    background-color: red;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import React from &#39;react&#39;;
import styles from &#39;./Styles.module.css&#39;;

const Button = () =&amp;gt; {
    return &amp;lt;button className={styles.error}&amp;gt;Error Button&amp;lt;/button&amp;gt;;
}

export default Button;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What will ensue is className will be unique, e.g. &lt;code&gt;Button_error_ax7yz&lt;/code&gt;, and specific styles will only be applied to this instance.&lt;/p&gt;
&lt;h4&gt;Caveats&lt;/h4&gt;
&lt;p&gt;There&#39;s a couple of nuances to this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Styles file has to have &lt;code&gt;.module.&lt;/code&gt; in its name - &lt;code&gt;Something.module.css&lt;/code&gt; or &lt;code&gt;Whatever.module.scss&lt;/code&gt;, but &lt;code&gt;.module.&lt;/code&gt; needs to be there.&lt;/li&gt;
&lt;li&gt;Class names shouldn&#39;t have dashes - &lt;code&gt;.error&lt;/code&gt; or &lt;code&gt;.errorButton&lt;/code&gt; would work, but &lt;code&gt;.error-button&lt;/code&gt; would not (in my case, IDE tries to be helpful and remove the dash, but it leads nowhere)&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <title>Keeping It Simple - Essential YC Advice And Thoughts</title>
        <link href="https://hydralien.net/blog//posts/keeping-it-simple-essential-yc-advise/"/>
        <updated>2023-05-14T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/keeping-it-simple-essential-yc-advise/</id>
        <content type="html">&lt;h4&gt;Personal Experience&lt;/h4&gt;
&lt;p&gt;I didn&#39;t have that much of an experience with startups and young projects myself - though I tried to build one with friends and work for another one afterwards.
But the ideas I want to cover here, even if immediately relevant to the startup kind of projects, are also applicable to the teams
and projects in the enterprise realm.&lt;/p&gt;
&lt;p&gt;I think the problem generally boils down to &amp;quot;over-engineering&amp;quot; and focusing too much on &amp;quot;doing things right&amp;quot;. In any project,
there should be a balance between how stable and properly done things are, and how fast the project is moving and changing:
if the focus is primarily on following (software) design methodologies, or building an uber-reusable solutions, the actual evolution
of the product would suffer, which essentially could lead to product&#39;s irrelevance and demise, which would render all efforts pretty much useless.&lt;/p&gt;
&lt;p&gt;And in case of young products/projects specifically, till there&#39;s a steady revenue and profitability, the product &lt;strong&gt;has to&lt;/strong&gt; evolve and change
rapidly and constantly - so any elaborate &amp;quot;by-the-book&amp;quot; solution will just bog it down, and become irrelevant very soon - &lt;strong&gt;especially&lt;/strong&gt; if the goal of the
development efforts is to create something super-flexible and adaptable. No amount of flexibility and adaptability will suit the reality of
a project that tries to find its place on the market, so spending efforts on it are counter-productive.&lt;/p&gt;
&lt;p&gt;On the other side of the spectrum would be building something very patchy and ad-hoc - but if that&#39;s a POC or a system that has no guarantee to live long,
it&#39;s very well justified: it will, most probably, be changed immensely quite soon - and in a super-rare case when it wouldn&#39;t it&#39;s easy to dismantle it and introduce
a solid replacement later on. There&#39;s no need to scale till there &lt;strong&gt;absolutely&lt;/strong&gt; is.&lt;/p&gt;
&lt;p&gt;Another aspect specifically relevant to the startups is they attract a skilled and opinionated individuals that are not necessarily
experienced in team work, and are eager to pursue a new solutions and fresh technologies, which are not necessarily meant for the
small projects, and would mean spending a lot of time on finding and solving issues. Boring is good, in this case  - so at some point
someone has to step up as a technical leader and people manager, and the sooner the better (also good if that person has a relevant experience).&lt;/p&gt;
&lt;h4&gt;YC Advice&lt;/h4&gt;
&lt;p&gt;That brings me to the YC advise part - &lt;a href=&quot;https://www.ycombinator.com/&quot;&gt;YCombinator&lt;/a&gt; has this article on their website,
&lt;a href=&quot;https://www.ycombinator.com/library/4D-yc-s-essential-startup-advice&quot;&gt;YC’s Essential Startup Advice&lt;/a&gt;,
which is a very useful advice altogether, but also has a succinct advice in the &amp;quot;The Pocket Guide of Essential YC Advice&amp;quot; section.&lt;/p&gt;
&lt;p&gt;Here&#39;s a copy of that section with comments in some places:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Launch now (&lt;em&gt;the sooner you do it, the sooner you&#39;d know what needs to change; building something longer means spending efforts on something that will not be relevant&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Build something people want&lt;/li&gt;
&lt;li&gt;Do things that don&#39;t scale&lt;/li&gt;
&lt;li&gt;Find the 90 / 10 solution&lt;/li&gt;
&lt;li&gt;Find 10-100 customers who love your product&lt;/li&gt;
&lt;li&gt;All startups are badly broken at some point (&lt;em&gt;and that&#39;s OK&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Write code - talk to users&lt;/li&gt;
&lt;li&gt;&amp;quot;It’s not your money&amp;quot; (&lt;em&gt;meaning, in the article&#39;s words, &amp;quot;You have a fiduciary and ethical/moral duty to spend the money only to improve the prospects of your company&amp;quot;&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Growth is the result of a great product, not the precursor&lt;/li&gt;
&lt;li&gt;Don’t scale your team/product until you have built something people want&lt;/li&gt;
&lt;li&gt;Valuation is not equal to success or even probability of success&lt;/li&gt;
&lt;li&gt;Avoid long negotiated deals with big customers if you can&lt;/li&gt;
&lt;li&gt;Avoid big company corporate development queries - they will only waste time&lt;/li&gt;
&lt;li&gt;Avoid conferences unless they are the best way to get customers&lt;/li&gt;
&lt;li&gt;Pre-product market fit - do things that don’t scale: remain small/nimble&lt;/li&gt;
&lt;li&gt;Startups can only solve one problem well at any given time&lt;/li&gt;
&lt;li&gt;Founder relationships matter more than you think&lt;/li&gt;
&lt;li&gt;Sometimes you need to fire your customers (they might be killing you)&lt;/li&gt;
&lt;li&gt;Ignore your competitors, you will more likely die of suicide than murder&lt;/li&gt;
&lt;li&gt;Most companies don&#39;t die because they run out of money&lt;/li&gt;
&lt;li&gt;Be nice! Or at least don’t be a jerk&lt;/li&gt;
&lt;li&gt;Get sleep and exercise - take care of yourself (&lt;em&gt;This one is super important - it&#39;s too easy to get into the &amp;quot;I have to do it all&amp;quot; mode, which burns you out in no time&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <title>Reddit RSS Feed Parsing/Proxying In Python</title>
        <link href="https://hydralien.net/blog//posts/python-reddit-rss-feed-parsing/"/>
        <updated>2023-07-29T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/python-reddit-rss-feed-parsing/</id>
        <content type="html">&lt;h4&gt;The problem&lt;/h4&gt;
&lt;p&gt;I like reading news via feed aggregators - and after the demise of Google Reader, I&#39;ve migrated to &lt;a href=&quot;https://feedly.com/&quot;&gt;Feedly&lt;/a&gt;.
Which is great by itself, and doesn&#39;t even need me to provide an URL of teh feed - it can use site URL, or even site name, to provide one.&lt;/p&gt;
&lt;p&gt;Also, I read some (very limited) streams on Reddits, such as &lt;a href=&quot;https://www.reddit.com/r/programming/&quot;&gt;r/programming/&lt;/a&gt; - but the problem is,
if I use just the feed directly, it points me to a post on Reddit, which I find fairly useless: I don&#39;t care about comments, I mostly
care about the content of the articles people post.&lt;/p&gt;
&lt;p&gt;So I wanted clicks on the item to lead me directly to the article, skipping the Reddit post.&lt;/p&gt;
&lt;h4&gt;The solution&lt;/h4&gt;
&lt;p&gt;The solution I came up with was to host a simple proxy that would accept feed name, get the feed XML from Reddit, parse it,
replace the post URL with article URL, and return the results. Since I have some apps running here and there, I could put it
on a server, so I didn&#39;t need to be concerned about CORS requests or any other browser security constraints.&lt;/p&gt;
&lt;p&gt;So the result is a simple Python app that uses &lt;a href=&quot;https://bottlepy.org/docs/dev/tutorial.html?highlight=static&quot;&gt;Bottle&lt;/a&gt; as HTTP server framework.
It doesn&#39;t do much, but it does what I need it to: &lt;a href=&quot;https://github.com/hydralien/tools/tree/master/reddit-streamline&quot;&gt;https://github.com/hydralien/tools/tree/master/reddit-streamline&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Example: &lt;a href=&quot;https://pidging.hydralien.net/direddit/?rss_path=r/programming/.rss&quot;&gt;https://pidging.hydralien.net/direddit/?rss_path=r/programming/.rss&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: I had to change the path handling from regex to query parameter in thw example app because conflicts in my Flask app with some other route handling mechanisms.&lt;/p&gt;
&lt;p&gt;It actually existed for a few years now, I just finally decided to upgrade it to Python3 and thought of posting it here.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Reviving Stale Flutter App For iOS and Android</title>
        <link href="https://hydralien.net/blog//posts/reviving-stale-flutter-app/"/>
        <updated>2023-09-29T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/reviving-stale-flutter-app/</id>
        <content type="html">&lt;h4&gt;The problem&lt;/h4&gt;
&lt;p&gt;I have a Flutter app I developed couple years back, PictureVert (source code: &lt;a href=&quot;https://github.com/hydralien/PictureVert&quot;&gt;https://github.com/hydralien/PictureVert&lt;/a&gt;).
It had been collecting proverbial dust for a while, so I decided to build ad deploy fresh packages for both iOS and Android.&lt;/p&gt;
&lt;p&gt;So I needed to figure out how to update everything and make it work again.&lt;/p&gt;
&lt;h4&gt;Flutter&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Install &lt;a href=&quot;https://docs.flutter.dev/get-started/install&quot;&gt;fresh Flutter&lt;/a&gt; and set its path in the &lt;code&gt;PATH&lt;/code&gt; variable (in e.g. &lt;code&gt;~/.profile&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;flutter pub outdated&lt;/code&gt; and &lt;code&gt;flutter pub upgrade&lt;/code&gt; (I had to do those iteratively because one points to another, but once is actually enough)&lt;/li&gt;
&lt;li&gt;Add new versions of stale packages via &lt;code&gt;flutter pub add packagename anotherpackagename ...&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Check &lt;code&gt;flutter pub outdated&lt;/code&gt; again - it seemed to have different concerns this time around&lt;/li&gt;
&lt;li&gt;Add what&#39;s missing via &lt;code&gt;flutter pub add&lt;/code&gt; and &lt;code&gt;flutter pub upgrade&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Check &lt;code&gt;flutter doctor&lt;/code&gt; to see all is well&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;iOS&lt;/h4&gt;
&lt;p&gt;Building for iOS got simpler, though requires some pre-steps:&lt;/p&gt;
&lt;h5&gt;Accept XCode license agreement&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;    sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
    sudo xcodebuild -runFirstLaunch
    sudo xcodebuild -license
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;Prepare dependencies&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;    xcodebuild -downloadPlatform iOS
    open -a Simulator
    cd ios; pod install; cd ..
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;Build and install&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;    flutter build ipa
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the end of teh build, some useful guidance is provided:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    Built IPA to /Users/halien/devel/picturevert/build/ios/ipa.
    To upload to the App Store either:
        1. Drag and drop the &amp;quot;build/ios/ipa/*.ipa&amp;quot; bundle into the Apple Transporter macOS app https://apps.apple.com/us/app/transporter/id1450874784
        2. Run &amp;quot;xcrun altool --upload-app --type ios -f build/ios/ipa/*.ipa --apiKey your_api_key --apiIssuer your_issuer_id&amp;quot;.
           See &amp;quot;man altool&amp;quot; for details about how to authenticate with the App Store Connect API key.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I decided to use the &amp;quot;Apple Transporter&amp;quot; way (#1) and it worked surprisingly smooth - the build appeared in the App Store Connect immediately, ready for testing and being plugged to a release,
so I just needed to provide an info about teh update and submit it for review.&lt;/p&gt;
&lt;h4&gt;Android&lt;/h4&gt;
&lt;p&gt;First, Google Play Store Console required updating the SDK versions, so in &lt;code&gt;android/local.properties&lt;/code&gt; I needed to set&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    flutter.minSdkVersion=24
    flutter.targetSdkVersion=33
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, things with Android were not that smooth - &lt;code&gt;flutter build appbundle&lt;/code&gt; started complaining &lt;em&gt;seemingly&lt;/em&gt; about one of the dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    * What went wrong:
    A problem occurred evaluating project &#39;:share_plus&#39;.
    &amp;gt; No signature of method: build_bkr51e9abrzl3n3k84uhu79f3.android() is applicable for argument types: (build_bkr51e9abrzl3n3k84uhu79f3$_run_closure2) values: [build_bkr51e9abrzl3n3k84uhu79f3$_run_closure2@94bf7f9]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But that&#39;s a deception: apparently the problem is incompatibility with old Gradle plugin, but to which version to update was unclear.&lt;/p&gt;
&lt;p&gt;So I ended up doing &lt;code&gt;flutter create newproject&lt;/code&gt; elsewhere, and then copying the supported versions from it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;from &lt;code&gt;android/gradle/wrapper/gradle-wrapper.properties&lt;/code&gt;, the &lt;code&gt;distributionUrl=https&#92;://services.gradle.org/distributions/gradle-7.5-all.zip&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;from &lt;code&gt;android/build.gradle&lt;/code&gt;, the &lt;code&gt;ext.kotlin_version = &#39;1.7.10&#39;&lt;/code&gt; and the &lt;code&gt;classpath &#39;com.android.tools.build:gradle:7.3.0&#39;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After that, &lt;code&gt;flutter build appbundle&lt;/code&gt; had finally succeeded.&lt;/p&gt;
&lt;p&gt;I also copied &lt;code&gt;sdk: &#39;&amp;gt;=3.1.3 &amp;lt;4.0.0&#39;&lt;/code&gt; from &lt;code&gt;pubspec.yaml&lt;/code&gt; of a fresh Flutter app, just to be sure.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Bun React JSX-Dev-Runtime Cannot Find Module / jsxDEV Is Not A Function Error</title>
        <link href="https://hydralien.net/blog//posts/bun-react-jsx-dev-runtime-cannot-find-module/"/>
        <updated>2024-10-02T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/bun-react-jsx-dev-runtime-cannot-find-module/</id>
        <content type="html">&lt;h3&gt;Preface&lt;/h3&gt;
&lt;p&gt;We&#39;re using Bun (https://bun.sh/) for some repositories - and as a still young project, it has some quirks. Recording one of those in case it&#39;s encountered elsewhere.&lt;/p&gt;
&lt;h4&gt;Error case&lt;/h4&gt;
&lt;p&gt;We had a situation when an NPM package built with Bun was working fine while using locally, and build that included the package passed well,
but when the final build (of the app that used the Bun-built package) was loaded from CDN, it failed with following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TypeError: (0 , yK.jsxDEV) is not a function
at C$ (index. )s:1:46881)
at of (react-dom.production.min.js:167:137) at s (react-dom.production.min. js:290:337) at sZ (react-dom production.min. js: 280:389) at react-dom.production.min.js:280:320
at sx (react-dom.production.min.js:280:325) at sB (react-dom.production.min.js:271:88)
at sW (react-dom-production.min.js:273:300) at iu (react-dom.production.min.js: 127:105) at react-dom.production.min.js:267:273
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When investigating locally, somewhat different behaviour was observed - the package was failing with the following error (package names generalised):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@parcel/core: Failed to resolve &#39;exportedThing&#39; from &#39;./node_modules/somepackage/dist/index.js&#39;

  /Users/user/devel/project/node_modules/somepackage/dist/index.js:1:34428
  &amp;gt; 1 |  from&amp;quot;exportedThing&amp;quot;;import{a as hs,b as ms}from&amp;quot;somePackage&amp;quot;;import{jsxDEV as gs}from&amp;quot;react/jsx-dev-runtime&amp;quot;;var Di=({children:i})=&amp;gt;{const{locale:e}=ms();return gs(hs,{locale:e,localeData:us,children:i}
  &amp;gt;   |      ^^^^^^^^^^^^^^^^^^
    2 |

@parcel/resolver-default: Cannot find module &#39;exportedThing&#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Those were somewhat obscure and misleading - the keywords are &amp;quot;&lt;strong&gt;jsxDEV&lt;/strong&gt;&amp;quot; and &amp;quot;&lt;strong&gt;react/jsx-dev-runtime&lt;/strong&gt;&amp;quot; - the app was running on production, yet required some dev resources.&lt;/p&gt;
&lt;h3&gt;Solution&lt;/h3&gt;
&lt;p&gt;The solution was to prefix the Bun build command in &lt;code&gt;package.json&lt;/code&gt; (for the package build) with &lt;code&gt;NODE_ENV=production&lt;/code&gt;, like e.g. in our case:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; &amp;quot;build&amp;quot;: &amp;quot;NODE_ENV=production bun build.ts&amp;quot;,
&lt;/code&gt;&lt;/pre&gt;
</content>
    </entry>
    
    <entry>
        <title>Git Merge Conflict Resolution And Learning Resource</title>
        <link href="https://hydralien.net/blog//posts/git-merge-conflict-resolution-and-learning-resource/"/>
        <updated>2024-11-22T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/git-merge-conflict-resolution-and-learning-resource/</id>
        <content type="html">&lt;h3&gt;Merge conflicts&lt;/h3&gt;
&lt;p&gt;When merging branches in Git repository, conflicts sometimes emerge. There&#39;s certainly a way to solve them manually,
but sometimes they&#39;re too large and don&#39;t actually matter (like e.g. yaml-lock in a Node project), and sometimes they should be resolved by picking everything from either branch.&lt;/p&gt;
&lt;p&gt;There&#39;s a way to use specific merge strategy to resolve everything either way:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git merge --no-ff -X theirs branchname
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git merge --no-ff -X ours branchname
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But sometimes it&#39;s not that trivial - sometimes some changes need to be resolved one way, and some the other.
In that case, when merge encountered conflicts, it&#39;s done like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git checkout --theirs [path/file]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git checkout --ours [path/file]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(also, &lt;code&gt;git add [path/file]&lt;/code&gt; still required afterwards to mark resolution)&lt;/p&gt;
&lt;h3&gt;Learning resource&lt;/h3&gt;
&lt;p&gt;There&#39;s a great resource that explains these - and much more, like what&#39;s &lt;code&gt;--no-ff&lt;/code&gt; - in great details: &lt;a href=&quot;https://craftquest.io/guides/git/git-workflow-tools/git-merge&quot;&gt;https://craftquest.io/guides/git/git-workflow-tools/git-merge&lt;/a&gt;&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Philips 65OLED Disable Factory Logo Screensaver</title>
        <link href="https://hydralien.net/blog//posts/philips-65oled-disable-logo-screensaver/"/>
        <updated>2024-11-29T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/philips-65oled-disable-logo-screensaver/</id>
        <content type="html">&lt;h4&gt;The background&lt;/h4&gt;
&lt;p&gt;I recently got a Philips 65OLED708 TV, based on Google TV. Gorgeous large screen, bright and vivid.
And since it&#39;s Google TV, it also has an &amp;quot;ambient&amp;quot; mode that can display, among other things, photos from Google Photos.
And I have plenty of those, so on the previous TV Chromecast did a good job displaying that.&lt;/p&gt;
&lt;h4&gt;&amp;quot;So far so what, but here&#39;s the thing&amp;quot;&lt;/h4&gt;
&lt;p&gt;The damn thing starts displaying black screen with white Philips logo jumping around after two minutes of inactivity!
And there&#39;s no way to set longer timeout or disable it in conventional settings, because they decided to safeguard users from &lt;a href=&quot;https://www.cnet.com/tech/home-entertainment/oled-burn-in-what-you-need-to-know-for-tvs-phones-and-more/&quot;&gt;OLED Burn-In&lt;/a&gt;.
So much for using the beautiful screen for anything apart from watching videos...
Now, Ambient mode has elements that can remain at one-ish place for a significant time (weather, time, album name),
but unlike that pesky Philips screensaver, they can all be disabled to leave just constantly changing images which would NOT cause burn-in.&lt;/p&gt;
&lt;h4&gt;Luckily, there are ways&lt;/h4&gt;
&lt;p&gt;After some googling, I found two reliable ways to do it - one (hopefully) more permanent, and another temporary but with more access to the system.&lt;/p&gt;
&lt;h5&gt;The (seemingly) permanent way&lt;/h5&gt;
&lt;p&gt;is to revoke the &amp;quot;&lt;strong&gt;Display over other apps&lt;/strong&gt;&amp;quot; permission from the &amp;quot;&lt;strong&gt;Tv System UI&lt;/strong&gt;&amp;quot; app, by following this path in TV menu:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Settings&lt;/li&gt;
&lt;li&gt;System&lt;/li&gt;
&lt;li&gt;Storage&lt;/li&gt;
&lt;li&gt;Internal shared storage&lt;/li&gt;
&lt;li&gt;Apps&lt;/li&gt;
&lt;li&gt;Special app access&lt;/li&gt;
&lt;li&gt;Display over other apps&lt;/li&gt;
&lt;li&gt;Finding &amp;quot;&lt;strong&gt;Tv System UI&lt;/strong&gt;&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;and disabling it. It still triggers (there&#39;s a temporary notification when it does), but it doesn&#39;t overlay the Ambient mode slideshow anymore.&lt;/p&gt;
&lt;h5&gt;The temporary way, on TV&lt;/h5&gt;
&lt;p&gt;is to stop the &lt;strong&gt;Tv System UI&lt;/strong&gt; app by navigating to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Settings&lt;/li&gt;
&lt;li&gt;System&lt;/li&gt;
&lt;li&gt;Storage&lt;/li&gt;
&lt;li&gt;Internal shared storage&lt;/li&gt;
&lt;li&gt;Apps&lt;/li&gt;
&lt;li&gt;See all apps&lt;/li&gt;
&lt;li&gt;Scroll to the bottom to find &amp;quot;Show system apps&amp;quot;&lt;/li&gt;
&lt;li&gt;Scroll all the way down to &amp;quot;Tv System UI&amp;quot; (&lt;strong&gt;NOT&lt;/strong&gt; &amp;quot;System UI&amp;quot;)&lt;/li&gt;
&lt;li&gt;Force-stop it&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It will come up on system restart though. And it&#39;s A LOT of scrolling.&lt;/p&gt;
&lt;h5&gt;The temporary way, on remote device (OSX laptop, in my case)&lt;/h5&gt;
&lt;p&gt;is unnecessary complex, but I&#39;ll leave it here in case I&#39;d ever need to do more with the TV, as is provides a way to connect to its internals with &lt;a href=&quot;https://developer.android.com/tools/adb&quot;&gt;Android Debug Bridge&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First, installing ADB:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Install &lt;a href=&quot;https://brew.sh/&quot;&gt;homebrew&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Install adb: &lt;code&gt;brew install android-platform-tools&lt;/code&gt; and check that it&#39;s available with &lt;code&gt;adb devices&lt;/code&gt; (result would be empty for now)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then (from &lt;a href=&quot;https://www.reddit.com/r/Chromecast/comments/s96moi/how_to_connect_to_ccwgtv_via_adb_using_only_wifi/&quot;&gt;https://www.reddit.com/r/Chromecast/comments/s96moi/how_to_connect_to_ccwgtv_via_adb_using_only_wifi/&lt;/a&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Find your Google TV&#39;s IP address and write it down to use later. Go to Settings &amp;gt; System &amp;gt; About &amp;gt; Status. Your IP address will be something like this made up example: 192.162.3.4 (ignore the long number that you&#39;ll see above the IP address).&lt;/li&gt;
&lt;li&gt;Enable Developer Options on your Google TV:
&lt;ul&gt;
&lt;li&gt;Settings &amp;gt; System &amp;gt; About.&lt;/li&gt;
&lt;li&gt;Scroll down to “Android TV OS Build” (Make sure it says BUILD not VERSION).&lt;/li&gt;
&lt;li&gt;Tap &lt;strong&gt;seven times&lt;/strong&gt;. You’ll see a message that says you’re now a Developer.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Enable USB Debugging on your Google TV:
&lt;ul&gt;
&lt;li&gt;Settings &amp;gt; System &amp;gt; Developer Options (if you don’t see this, then the previous step did not complete successfully)&lt;/li&gt;
&lt;li&gt;In Developer Options, ensure Enable Developer Options is toggled on.&lt;/li&gt;
&lt;li&gt;Scroll down to USB Debugging and toggle it on.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Make sure your Google TV and your computer are on the same WiFi network.&lt;/li&gt;
&lt;li&gt;In shell, run &lt;code&gt;adb connect [your Google TV IP address from Step 1]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;On the TV, you&#39;ll see a message like this: &amp;quot;Allow USB debugging?&amp;quot;; allow it (with TV remote).&lt;/li&gt;
&lt;li&gt;Back in the command window, you&#39;ll probably see something like this: &amp;quot;failed to authenticate to 192.162.3.4&amp;quot;. That&#39;s OK - if you try e.g. &lt;code&gt;adb connect 192.162.3.4&lt;/code&gt; again, it&#39;d say &amp;quot;already connected to 192.162.3.4&amp;quot;&lt;/li&gt;
&lt;li&gt;To check that you&#39;re connected, list the connected devices with &lt;code&gt;adb devices&lt;/code&gt; - should be e.g. &amp;quot;192.164.3.4:5555 device&amp;quot;&lt;/li&gt;
&lt;li&gt;To disconnect (when needed): &lt;code&gt;adb disconnect 192.162.3.4&lt;/code&gt;. Reconnection would require confirming it on TV again.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;adb shell am force-stop org.droidtv.tvsystemui&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That does pretty much the same as what could be done manually - benefit is, it could be done faster than in UI once everything is set up,
and ADB would allow a lot more if needed.&lt;/p&gt;
&lt;h4&gt;Tada!&lt;/h4&gt;
&lt;p&gt;Here&#39;s one of the photos to emphasise the importance of having the ambient mode:&lt;/p&gt;
&lt;img src=&quot;https://lh3.googleusercontent.com/pw/AP1GczMFRo4RtaeVFnE8xeN3qlWGMFoyqIKT3En33BhsVua91IgtqKOjeWEQPhdBoedjT7vjFVUSquY7uXIlvyq8YDQkqizBNFpAjPBqQ_gCNwE9s2g3Eb6WfQ1e87THO_fMkEuOHGf0oYEVA7PqjbYuEq5kLA=w2116-h1410-s-no-gm?authuser=0&quot; alt=&quot;Bank Of Beckenried&quot; style=&quot;width: 90%&quot; /&gt;</content>
    </entry>
    
    <entry>
        <title>Picturevert Update And New Features</title>
        <link href="https://hydralien.net/blog//posts/picturevert-update-new-features/"/>
        <updated>2024-12-19T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/picturevert-update-new-features/</id>
        <content type="html">&lt;img src=&quot;https://hydralien.net/blog/assets/picturevert_logo.png&quot; alt=&quot;Picturevert logo&quot; style=&quot;width: 150px; border-radius: 1em;&quot; /&gt;
&lt;h4&gt;Update&lt;/h4&gt;
&lt;p&gt;Since I had some time and wanted to try some ideas, I&#39;ve updated the Picturevert app with some new features - so now it&#39;s capable of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Selecting any image from the photo gallery.&lt;/li&gt;
&lt;li&gt;Taking an instant photo and applying effects sto it immediately.&lt;/li&gt;
&lt;li&gt;Inverting image colors with a variable degree of color shift.&lt;/li&gt;
&lt;li&gt;Making a multi-direction color trail from any point of picture with varied jitter and thickness.&lt;/li&gt;
&lt;li&gt;Mirroring halves of the picture in 4 directions.&lt;/li&gt;
&lt;li&gt;Exporting the result by using standard sharing mechanism.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most fun was to implement color &amp;quot;smudge&amp;quot;, since I wanted to make lines of variable width but with averaged color, and also with some jitter of starting point.
Given that image comes as a list of values for pixels, but each pixel is actually 3 elements in array (RGB), that required some thinking.&lt;/p&gt;
&lt;p&gt;Mirroring was fun too, because it wasn&#39;t just reversing half of the list - had to be done for each line and in iterations of 3 (because RGB).&lt;/p&gt;
&lt;h4&gt;Results&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://hydralien.net/picturevert&quot;&gt;App page with store links&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/hydralien/PictureVert&quot;&gt;Code on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <title>In Vitest, Order Of Import Matters For Mocks</title>
        <link href="https://hydralien.net/blog//posts/vitest-order-of-import-matters-for-mocks/"/>
        <updated>2025-02-06T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/vitest-order-of-import-matters-for-mocks/</id>
        <content type="html">&lt;h3&gt;Cutting to the chase&lt;/h3&gt;
&lt;p&gt;In Vitest, this would work:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    import {test, expect, vi} from &amp;quot;vitest&amp;quot;;
    import round from &amp;quot;lodash.round&amp;quot;;
    
    vi.mock(&amp;quot;lodash.round&amp;quot;, () =&amp;gt; {
        return {
            default: (value) =&amp;gt; 33
        }
    })
     
    test(&amp;quot;roundup&amp;quot;, () =&amp;gt; {
        const no = 5.7;
        expect(round(no)).toBe(33);
    });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;however if the mock is extracted to another file (say, to be reused across several tests), test will fail if it&#39;s imported after actual package it mocks:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    import {test, expect, vi} from &amp;quot;vitest&amp;quot;;
    import round from &amp;quot;lodash.round&amp;quot;;
    import _ from &amp;quot;./roundmock&amp;quot;;
    
    test(&amp;quot;roundup&amp;quot;, () =&amp;gt; {
        const no = 5.7;
        expect(round(no)).toBe(33);
    });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;because the mock is imported after the actual package.
This, however, will pass (note that the only difference is the order of imports):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    import {test, expect, vi} from &amp;quot;vitest&amp;quot;;
    import _ from &amp;quot;./roundmock&amp;quot;;
    import round from &amp;quot;lodash.round&amp;quot;;
    
    test(&amp;quot;roundup&amp;quot;, () =&amp;gt; {
        const no = 5.7;
        expect(round(no)).toBe(33);
    });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I guess that&#39;s because Vitest is hoisting mocks withing the file to happen before the imports, but if they&#39;re in separate files - the import will happen in actual import order.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Picturevert Update Two Way Mirroring</title>
        <link href="https://hydralien.net/blog//posts/picturevert-two-way-mirroring/"/>
        <updated>2025-02-08T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/picturevert-two-way-mirroring/</id>
        <content type="html">&lt;h4&gt;Update&lt;/h4&gt;
&lt;p&gt;Added two-way image mirroring to the &lt;a href=&quot;https://hydralien.net/picturevert&quot;&gt;Picturevert&lt;/a&gt; - even more fun now:&lt;/p&gt;
&lt;img src=&quot;https://res.cloudinary.com/dmhd8lsl2/image/upload/v1739021372/hydralien.net/IMG_4610_tsjvgx.jpg&quot; alt=&quot;Two-way mirroring with Picturevert&quot; style=&quot;width: 90%; border-radius: 1em;&quot; /&gt;
</content>
    </entry>
    
    <entry>
        <title>My Own Short Fiction Collection</title>
        <link href="https://hydralien.net/blog//posts/my-own-short-fiction-collection/"/>
        <updated>2025-02-12T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/my-own-short-fiction-collection/</id>
        <content type="html">&lt;h4&gt;The Gist&lt;/h4&gt;
&lt;p&gt;For since I can remember, I&#39;ve been collecting some ideas from everywhere that I was hoping one day to turn into something - but I wasn&#39;t sure into what, exactly.
So I decided to try it with text - and here&#39;s the result, a set of &lt;a href=&quot;https://hydralien.net/fiction&quot;&gt;short fictional stories&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;No particular connection between the stories, nothing sophisticated - but I kinda like the result.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Failure In Complex Systems</title>
        <link href="https://hydralien.net/blog//posts/failure-in-complex-systems/"/>
        <updated>2025-05-20T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/failure-in-complex-systems/</id>
        <content type="html">&lt;h4&gt;&amp;quot;The potential for catastrophic outcome is a hallmark of complex systems&amp;quot;&lt;/h4&gt;
&lt;p&gt;This is primarily a set of quotes from a great (and short) manifesto-like paper &amp;quot;&lt;a href=&quot;https://www.adaptivecapacitylabs.com/HowComplexSystemsFail.pdf&quot;&gt;How Complex Systems Fail&lt;/a&gt;&amp;quot; by late &lt;a href=&quot;https://en.wikipedia.org/wiki/Richard_Cook_(safety_researcher)&quot;&gt;Dr. Richard I. Cook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I fully agree with the points gathered in that paper, so I thought I&#39;d save it here along with most powerful (IMO) quotes.&lt;/p&gt;
&lt;p&gt;And as another reference, this paper came to my attention via another article, &amp;quot;&lt;a href=&quot;https://surfingcomplexity.blog/2025/05/19/not-causal-chains-but-interactions-and-adaptations/&quot;&gt;Not causal chains, but interactions and adaptations&lt;/a&gt;&amp;quot;, which IMO is a little vague but still touches an important point that the &lt;em&gt;Root Cause Analysis&lt;/em&gt; (RCA) is an obsolete and misleading practice that masks the actual nature of failures in any complex system.&lt;/p&gt;
&lt;p&gt;So here goes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;The complexity of these systems makes it impossible for them to run without multiple flaws being present ... The failures change constantly because of changing technology, work organization, and efforts to eradicate failures&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;The potential for catastrophic outcome is a hallmark of complex systems&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;no isolation of the ‘root cause’ of an accident is possible. The evaluations based on such reasoning as ‘root cause’ do not reflect a technical understanding of the nature of failure but rather the social, cultural need to blame specific, localized forces or events for outcomes.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Hindsight bias remains the primary obstacle to accident investigation, especially when expert human performance is involved.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;all practitioner actions are actually gambles, that is, acts that take place in the face of uncertain outcomes ... in general, post hoc analysis regards these gambles as poor ones. But the converse: that successful outcomes are also the result of gambles; is not widely appreciated. &amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Recognizing hazard and successfully manipulating system operations to remain inside
the tolerable performance boundaries requires intimate contact with failure.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And one more, not as a reason against new technology, but as an observation of potential impact that needs to be considered:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;When new technologies are used to eliminate well understood system failures or to gain high precision performance they often introduce new pathways to large scale, catastrophic failures. Not uncommonly, these new, rare catastrophes have even greater impact than those eliminated by the new technology.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
</content>
    </entry>
    
    <entry>
        <title>Flickr Alternatives And DIY Option</title>
        <link href="https://hydralien.net/blog//posts/flickr-alternatives-and-diy-option/"/>
        <updated>2025-12-29T00:00:00Z</updated>
        <id>https://hydralien.net/blog//posts/flickr-alternatives-and-diy-option/</id>
        <content type="html">&lt;p&gt;Also available &lt;a href=&quot;https://www.linkedin.com/pulse/flickr-alternatives-diy-option-borys-turchyk-bprsc&quot;&gt;as a LinkedIn article&lt;/a&gt;!&lt;/p&gt;
&lt;h4&gt;The Background&lt;/h4&gt;
&lt;p&gt;I&#39;ve been using Flicks as a place to host my annual photo galleries for quite some time, since 2013. And as ancient and rigid Flickr is,
it still does few things well, or at least well enough. Namely, the gallery display - it&#39;s not ideal but it does what it should: shows photos and related information such as title, description etc.
Sure, there are ads, and it&#39;s clunky, but it&#39;s tolerable, and my photos are not that important to make a fuss over the presentation; I just like them being available to view.&lt;/p&gt;
&lt;h4&gt;The Problem&lt;/h4&gt;
&lt;p&gt;Flickr&#39;s free tier limit of 1000 items worked for me for a long while as I only add some 50-80 photos a year, but it wsa inevitable that it runs out some day. And so the day has come.
I don&#39;t mind paying for services, but given that Flickr interface and UX is not great, IMO it&#39;s not worth the price, and other extras they include in the Pro tier do not interest me: I just need a photo gallery, that&#39;s all.&lt;/p&gt;
&lt;h4&gt;The Solutions That Were Not&lt;/h4&gt;
&lt;p&gt;There are quite a few alternatives out there, and I&#39;ve tried several - but none worked for my case, for various reasons:&lt;/p&gt;
&lt;h5&gt;Google Photos&lt;/h5&gt;
&lt;p&gt;I already use Google Photos for personal photo storage (its key advantage is, it serves as a image source for the smart TV screensaver), so having a dedicated album for annual &amp;quot;best of&amp;quot; collection was a logical choice.
However, the problem with Google Photos is when public link is created, it automatically shares the album with people who view it, if they&#39;re logged in to Google (and many people are), and so not only the album appears as shared in their Photos, I also see them in the shared list - and that&#39;s not at all what I want.&lt;/p&gt;
&lt;h5&gt;500px&lt;/h5&gt;
&lt;p&gt;Looked promising, good price, but editing photo title/description after upload was a major pain, and then what killed this option for me was gallery view mode - even though I chose paid account, for the non-logged-in viewers the gallery showed a blocking ad pop-up that required to wait for a few seconds, and then click a &amp;quot;Proceed&amp;quot; button, and then after a few photos it appeared again.
That&#39;s just utter disrespect to both viewers who&#39;d like to see the photos, and authors who want their photos viewed. I get the ads, but not blocking adds. That&#39;s just abhorrent.&lt;/p&gt;
&lt;h5&gt;Photobucket&lt;/h5&gt;
&lt;p&gt;Nice and clean photo upload, but viewing gallery looks like a stock NPM photo library and doesn&#39;t show any photo caption/details till user finds the info icon. For the price that tops the Flickr, that looked underwhelming.&lt;/p&gt;
&lt;h5&gt;Ente&lt;/h5&gt;
&lt;p&gt;Good price and generally simplistic interface (which is good), but viewer experience was more like a management interface than a photo gallery. This would&#39;ve probably been my option had the DYI approach (described below) failed.&lt;/p&gt;
&lt;h5&gt;Others (Instagram, Dropbox, Shutterfly etc.)&lt;/h5&gt;
&lt;p&gt;There were other options too, but they all had downsides - too much a social network, too business-oriented, too fearmongering marketing strategy (I&#39;m looking at you, Dropbox) etc.&lt;/p&gt;
&lt;h4&gt;The Solution&lt;/h4&gt;
&lt;p&gt;With the research above yielding unsatisfactory results, I thought that I already have another place to put the photo assets, that being Cloudinary - I use it for photos, screenshots and various images I use here in blog or on website or elsewhere.
I knew that Cloudinary has a rich image/video transformation/presentation layer, so I gathered it must have plenty of libraries I could use to build own solution. And on top of that, open-source image gallery libraries were always abundant for any platform, so I was certain there&#39;d be something for Vue (which is what my portfolio website is using).&lt;/p&gt;
&lt;p&gt;And both were certainly true:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://cloudinary.com/&quot;&gt;Cloudinary&lt;/a&gt; has guidance for Vue (among other systems such as React, Angular, pure JS and more): https://cloudinary.com/documentation/vue_sample_projects&lt;/li&gt;
&lt;li&gt;There&#39;s a lot of photo galleries for Vue to pick from - &lt;a href=&quot;https://primevue.org/galleria/&quot;&gt;Galleria&lt;/a&gt;, &lt;a href=&quot;https://photoswipe.com/vue-image-gallery/&quot;&gt;PhotoSwipe&lt;/a&gt;, &lt;a href=&quot;https://www.npmjs.com/package/vue-gallery&quot;&gt;vue-gallery&lt;/a&gt; and so on. I&#39;ve picked &lt;a href=&quot;https://www.lightgalleryjs.com/docs/vue-image-video-gallery/&quot;&gt;lightGallery&lt;/a&gt; as the one that seemed most suitable for my needs OOB.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With a bit of Cursoring (which essentially did exactly what I&#39;d done with copy-pasting, only much faster) and certain amount of cursing (see caveats below), it all worked out, so here it is, my &lt;a href=&quot;https://hydralien.net/gallery/2025&quot;&gt;best photos of 2025 here on personal website&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Caveats&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;The solution is very rudimentary as I had very little time, so the year is hardcoded, there&#39; no galleries list (and there&#39;s no other galleries yet), and there&#39;s no dedicated upload.&lt;/li&gt;
&lt;li&gt;Cloudinary&#39;s internal upload is good, and tagging is easy, but adding extra information such as caption and description is tedious. Not much tedious than 500px though, but this one&#39;s for free.&lt;/li&gt;
&lt;li&gt;The solution uses &lt;a href=&quot;https://cloudinary.com/documentation/list_assets&quot;&gt;Cloudinary CDN listing&lt;/a&gt; functionality, which required un-disabling &amp;quot;Resource list&amp;quot; resource in Security settings, and is not the best approach as it allows anyone to list all my public resources. Works for my case, but anything more complex would need a backend.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Pros&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Cloudinary is a generous platform for non-profit creators, and the functionality they provide is amazing. So for now, it&#39;s free.&lt;/li&gt;
&lt;li&gt;The technology is well known to me, so I have a freedom to adjust is as I please, expanding however I want. With modern LLM tools, it&#39;s also fast.&lt;/li&gt;
&lt;li&gt;It&#39;s all within my website now, which is a set of static pages hosted on &lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt; (another amazing service with a great free tier)&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
</feed>