<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Untitled Publication]]></title><description><![CDATA[Untitled Publication]]></description><link>https://blog.vadimfrolov.com</link><generator>RSS for Node</generator><lastBuildDate>Tue, 14 Apr 2026 11:36:57 GMT</lastBuildDate><atom:link href="https://blog.vadimfrolov.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Updates]]></title><description><![CDATA[These days, I feel like I spend a third of my time on the PC applying updates, another third logging into systems, and the rest just waiting for content to load.]]></description><link>https://blog.vadimfrolov.com/updates</link><guid isPermaLink="true">https://blog.vadimfrolov.com/updates</guid><category><![CDATA[Design]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Tue, 08 Apr 2025 19:55:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1744141357211/3a19d0b4-4caa-4fce-9f36-6c5674459b08.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>These days, I feel like I spend a third of my time on the PC applying updates, another third logging into systems, and the rest just waiting for content to load.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1744142088761/1aec8c6b-fddb-4b35-bd10-cb197a12bbb7.gif" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Python functions in Excel]]></title><description><![CDATA[Excel now supports Python. The documentation doesn’t describe how one can use python functions and I spent some time figuring this out. Imagine that you would like to create a set of your own function that you’d like to apply to values in your Excel ...]]></description><link>https://blog.vadimfrolov.com/python-functions-in-excel</link><guid isPermaLink="true">https://blog.vadimfrolov.com/python-functions-in-excel</guid><category><![CDATA[excel]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Fri, 22 Nov 2024 09:21:51 GMT</pubDate><content:encoded><![CDATA[<p>Excel now supports Python. The documentation doesn’t describe how one can use python functions and I spent some time figuring this out. Imagine that you would like to create a set of your own function that you’d like to apply to values in your Excel sheet. Here is what you need to do:</p>
<ol>
<li><p>Best place to put your python code is in the first cell of the first row. Python execution goes row by row. If you’d like, you can add a first sheet and call it something like <code>PythonInit</code>, then proceed with your regular Excel data on another sheet.</p>
</li>
<li><p>To call a function with the content of cell <code>A4</code> write <code>=PY(your_func_name(xl(“A4”)))</code></p>
</li>
</ol>
<p>Here is an illustration. I put this code in the first cell:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> base64

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">base64_converter</span>(<span class="hljs-params">input_text</span>):</span>
    <span class="hljs-string">"""
    Converts text to base64 or decodes base64 to text.
    Automatically detects the appropriate direction.

    Args:
        input_text (str): Input string to be encoded or decoded.

    Returns:
        str: Encoded or decoded result.
    """</span>
    <span class="hljs-keyword">try</span>:
        <span class="hljs-comment"># Attempt to decode input as Base64</span>
        decoded_text = base64.b64decode(input_text, validate=<span class="hljs-literal">True</span>).decode(<span class="hljs-string">'utf-8'</span>)
        <span class="hljs-keyword">return</span> decoded_text
    <span class="hljs-keyword">except</span> (ValueError, UnicodeDecodeError):
        <span class="hljs-comment"># If decoding fails, encode as Base64</span>
        encoded_text = base64.b64encode(input_text.encode(<span class="hljs-string">'utf-8'</span>)).decode(<span class="hljs-string">'utf-8'</span>)
        <span class="hljs-keyword">return</span> encoded_text
</code></pre>
<p>The result of this cell is a Python object.</p>
<p>Then I can call my function, which results in this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732267081588/4e3688d9-565c-4f5b-9e6e-e0525120106e.png" alt class="image--center mx-auto" /></p>
<p>The regular Excel’s magic like auto fill with increment works with python functions as well. Neat!</p>
]]></content:encoded></item><item><title><![CDATA[Phone Tray in BMW 330]]></title><description><![CDATA[I recently rented a new BMW 330. It was a nice ride, but the phone tray's design was terrible. You can see it in the photo:

The phone should be placed deep in the tray where the wireless charger is located, making it almost invisible and easy to for...]]></description><link>https://blog.vadimfrolov.com/phone-tray-in-bmw-330</link><guid isPermaLink="true">https://blog.vadimfrolov.com/phone-tray-in-bmw-330</guid><category><![CDATA[Design]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Thu, 14 Nov 2024 10:35:20 GMT</pubDate><content:encoded><![CDATA[<p>I recently rented a new BMW 330. It was a nice ride, but the phone tray's design was terrible. You can see it in the photo:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731580355159/7744664a-7729-4f4e-b25f-35d284363a32.png" alt class="image--center mx-auto" /></p>
<p>The phone should be placed deep in the tray where the wireless charger is located, making it almost invisible and easy to forget. The USB port and cup holders are positioned in front of the tray, making it difficult to retrieve the phone when occupied. If you don't use the dedicated tray, there's no other place for the phone, especially if it's connected by cable.</p>
<p>Compare BMW layout with Dodge's design:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731580381215/2f1def64-c01f-4719-b8c4-932ebbe24f2e.jpeg" alt class="image--center mx-auto" /></p>
<p>The organisation is improved. The phone can be easily accessed even if there is coffee in the cup holders. Additionally, the phone's placement is not too deep, making it convenient to retrieve.</p>
<p>Or take Skoda with its multimedia holder. You lose one cup holder, but there is a convenient and accessible place to put your phone.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731580410629/d0f20bbc-fea2-46a3-97d8-3b7aef82b42f.webp" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Summiting Mt. Whitney in November 2024]]></title><description><![CDATA[In November 2024, I made a second attempt to climb Mt. Whitney, which is the highest point in the lower 48 states and attracts many visitors. My first attempt was in 2016, solo, via a Mountaineering Route. I did not summit at that time, so I decided ...]]></description><link>https://blog.vadimfrolov.com/summiting-mt-whitney-in-november-2024</link><guid isPermaLink="true">https://blog.vadimfrolov.com/summiting-mt-whitney-in-november-2024</guid><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Tue, 12 Nov 2024 10:28:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1731406593816/a9f1a2f9-f6d9-468b-b5c5-afbf7147ea06.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In November 2024, I made a second attempt to climb Mt. Whitney, which is the highest point in the lower 48 states and attracts many visitors. My first attempt was in 2016, solo, via a Mountaineering Route. I did not summit at that time, so I decided to return. This post contains information about the mountain, things to know if you plan to go, useful links.</p>
<p>There is a lot of information about hiking Mt. Whitney. I won’t go into all the details and will provide links to other more in-depth descriptions.</p>
<h2 id="heading-when-to-go">When to go</h2>
<p>A permit is required to visit Mt. Whitney, with a lottery system in place from May to November. Since I live outside the US, I prefer going off season. From November 1st, permits are available without the lottery, though the weather can be unpredictable. Early November usually offers warm days and nights. Check the forecast at <a target="_blank" href="https://www.mountain-forecast.com/peaks/Mount-Whitney/forecasts/3500">https://www.mountain-forecast.com/peaks/Mount-Whitney/forecasts/3500</a> . This link allows you to check the weather at different elevation. The weather changes rapidly!</p>
<h2 id="heading-which-route-to-take">Which route to take</h2>
<p>The mountaineers' route is fun but dangerous, requiring preparation and technical skills. We chose the main trail, so the following details pertain to it. However, I include a paragraph about my mistakes on Mountaineering Route.</p>
<h2 id="heading-single-day-or-overnight">Single day or overnight</h2>
<p>Sleeping on the mountain in November means temperatures can drop below freezing. While it's manageable inside a tent, you'll need warm gear. My sleeping pad (R-value 5.9) and down sleeping bag together weigh 2.5 kg (5.51 lb). My friend, however, used a pad with an R-value of 3.8 and a synthetic sleeping bag for cold weather and was also fine.</p>
<p>Most people climb Mt. Whitney as a day hike, but it takes time, especially with November's short daylight from 6:20 to 16:20. I opted for a 2-day hike. If you're at the summit around sunset, you get an extra hour of light. Navigating the trail with a headlight is easy as it's well-marked, so starting at 1-2 a.m. and returning in the dark is feasible. The hike is very long, so carrying less weight makes it easier.</p>
<p>We combined both approaches. We hiked to Trail Camp with heavy backpacks, summited the same day, and returned to Trail Camp for the night. The next day, we hiked back to the trailhead. I failed to realize in advance how long it would take us to reach the Trail Camp, so we arrived too early to call it a day. We started at ca 06:00 and reached the Trail Camp by 11.</p>
<p><strong>Pro tip</strong>: if you setup a tent and plan to return in the dark – mark its location on your phone/map! 😉</p>
<h2 id="heading-the-trail">The trail</h2>
<p>The trail is very visible and marked well (at least when there is no snow). We had no trouble finding it. The only tricky sections were just after the summit (a plateau with many possible paths) and at Trail Camp in the dark (small detours to camp sites).</p>
<p><strong>Nevertheless, be sure to grab a GPX file with the trail and some sort of GPS device (either your phone or a dedicated device). It’s always good to have one with you.</strong></p>
<p>Given its popularity and length, additional distance markers along the way would be helpful. I found it useful to print out trail details for reference (credit goes to <a target="_blank" href="https://www.willtravelforsunsets.com/post/everything-and-anything-you-need-to-know-for-a-2-day-mt-whitney-hike">https://www.willtravelforsunsets.com/post/everything-and-anything-you-need-to-know-for-a-2-day-mt-whitney-hike</a>):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731359383894/d069f5c3-9209-4281-91ce-44b8d0c873f6.png" alt class="image--center mx-auto" /></p>
<p>The above table is based on the following sheet: <a target="_blank" href="https://docs.google.com/spreadsheets/d/e/2PACX-1vT2B5BrEUKJsQT26-ndVqt_ixp0S96iz0PRbORbNOtZn2VddPA5ImOsGiMqs8KOm1Vfg0ZQ09v8b_OM/pubhtml?gid=0&amp;single=true&amp;widget=true&amp;headers=false">https://docs.google.com/spreadsheets/d/e/2PACX-1vT2B5BrEUKJsQT26-ndVqt_ixp0S96iz0PRbORbNOtZn2VddPA5ImOsGiMqs8KOm1Vfg0ZQ09v8b_OM/pubhtml?gid=0&amp;single=true&amp;widget=true&amp;headers=false</a></p>
<h2 id="heading-trip-in-numbers">Trip in numbers</h2>
<p>Number of US elections happened during the trip: <strong>1</strong><br />Total miles driven in a rented vehicle: <strong>1626</strong> (<strong>2616</strong> km)<br />People met on the first day: <strong>11</strong><br />People met on the second day: <strong>5</strong><br />Solo hikers: <strong>4</strong><br />People who didn’t summit: <strong>1</strong><br />People with an ice axe: <strong>1</strong><br />Alcohol consumed before the hike: <strong>2</strong> beers + <strong>1</strong> whisky shot; <strong>1</strong> small beer.<br />Alcohol consumed right after the hike: <strong>1</strong> beer.<br />Average weight of backpacks: <strong>42</strong> lb (<strong>19</strong> kg)<br />Ping pong sets played in Lone Pine: <strong>4</strong><br />American pool games played in Lone Pine: <strong>1</strong><br />Times thinking about jumping in a swimming pool or a lake: <strong>2</strong><br />Times actually jumping in a swimming pool or a lake: <strong>0</strong><br />Snickers bars consumed during the trip: <strong>0.5</strong></p>
<h3 id="heading-mistakes-for-mountaineering-route-in-2016">Mistakes for Mountaineering Route in 2016</h3>
<p>Here is what I think are my mistakes for not making it back in 2016:</p>
<ul>
<li><p>Going solo on a more challenging route</p>
</li>
<li><p>Not preparing physically (I think I did train a bit, but not really with a backpack)</p>
</li>
<li><p>Not staying focused on my goal - visited friends on the way to Lone Pine → delayed → arrived late for grabbing the permit the same day → late departure to the trail</p>
</li>
<li><p>Not testing my tent beforehand. I bought a new tent just a couple of days prior the trip and didn’t test it on the ground. To put it on the mountain during sunset when I was tired and sick from altitude was an extra challenge.</p>
</li>
</ul>
<h2 id="heading-links">Links</h2>
<ul>
<li><p>Basically all you want to know about the hike - <a target="_blank" href="https://hikingguy.com/hiking-trails/hikes-around-mt-whitney/mt-whitney-hike/">https://hikingguy.com/hiking-trails/hikes-around-mt-whitney/mt-whitney-hike/</a></p>
</li>
<li><p><a target="_blank" href="https://www.willtravelforsunsets.com/post/everything-and-anything-you-need-to-know-for-a-2-day-mt-whitney-hike">https://www.willtravelforsunsets.com/post/everything-and-anything-you-need-to-know-for-a-2-day-mt-whitney-hike</a></p>
</li>
<li><p>Gear rental - <a target="_blank" href="https://www.lowergear.com/">https://www.lowergear.com/</a> . They have a dedicated Mt Whitney package. Worked great for me as I grabbed the gear from their shop in Phoenix.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Bugs around us: Air France]]></title><description><![CDATA[Wow! What a day! Today was one of those were technology just wasn't on my side, and the experience with Air France clearly stood out. I was searching for flight tickets from my phone, expecting it to be a smooth experience (well, if searching for fli...]]></description><link>https://blog.vadimfrolov.com/bugs-around-us-air-france</link><guid isPermaLink="true">https://blog.vadimfrolov.com/bugs-around-us-air-france</guid><category><![CDATA[UX]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Thu, 05 Sep 2024 18:36:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1725560988793/7f67788c-51d6-4898-a831-e46a35f502c5.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Wow! What a day! Today was one of those were technology just wasn't on my side, and the experience with Air France clearly stood out. I was searching for flight tickets from my phone, expecting it to be a smooth experience (well, if searching for flight tickets could ever be smooth), but instead, I found myself stuck in a digital maze.</p>
<p>It all started when I decided to create an account with Air France. It seemed like a good idea - especially, since my company has a partnership with Air France. The process, as usual, required an email verification. No big deal, right? But while I was fetching the verification code, the website decided to reset. I had to start the entire registration process from scratch: name, date of birth, email, phone number, and all the rest. They almost lost me there.</p>
<p>Okay, maybe websites can have bad days. I figured switching to Air France app might be more stable. So I downloaded the app, entered all my details yet again, and retrieved the verification code. But this time, things went even more frustrating. Pop-ups appearing on the screen, interrupting the flow. Just when I thought I was almost done, the app went into limbo, leaving me nothing but frustration.</p>
<p>This experience is a classic example of how we’ve overcomplicated the digital world. Instead of focusing on making things simple and intuitive, many companies add layers of unnecessary complexity. Too many steps, too many pop-ups, too many things that can go wrong. Too many cookie banners too! It's easy to forget that, more often than not, simple solutions are the best ones. So, next time you’re designing a system, remember: less is often more. Keep it simple, and everyone wins.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725562282361/b2bffdcc-1c46-4df4-97d0-a3724529ca42.jpeg" alt class="image--center mx-auto" /></p>
<p>PS. And as a bonus. Air France app doesn't trim trailing spaces, which are added automatically by keyboard suggestions on smartphones. This seemingly small oversight leads to repeated errors when entering usernames or passwords. On top of that, the app enforces ridiculous password requirements—demanding a perfect combination of uppercase, lowercase, numbers, symbols, and a specific length—without any flexibility. These overly strict rules not only make the experience more frustrating but also contribute to the growing complexity that turns a simple task into a cumbersome ordeal.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725562301269/b4e38ac2-057a-449d-b10d-e67ae7e33db5.jpeg" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Modern gaming]]></title><description><![CDATA[The thing I hate about modern console gaming - inability to do one room multi-player. Or cross play or whatever it is called. It freaks me out every time. I need to Google, try things, create additional user accounts. All these when my kid is around ...]]></description><link>https://blog.vadimfrolov.com/modern-gaming</link><guid isPermaLink="true">https://blog.vadimfrolov.com/modern-gaming</guid><category><![CDATA[Design]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Fri, 12 Jul 2024 12:01:28 GMT</pubDate><content:encoded><![CDATA[<p>The thing I hate about modern console gaming - inability to do one room multi-player. Or cross play or whatever it is called. It freaks me out every time. I need to Google, try things, create additional user accounts. All these when my kid is around and constantly asking me when are we going to start playing.</p>
]]></content:encoded></item><item><title><![CDATA[Farewell Gitlab]]></title><description><![CDATA[I like to look at different options. Github is not my default go-to solution for git. I used Gitlab, Bitbucket and even bare minimum systems that look like git2web (KDE, NemoMobile).
I have one project at Gitlab that consist of 3 repos. Recently I wa...]]></description><link>https://blog.vadimfrolov.com/farewell-gitlab</link><guid isPermaLink="true">https://blog.vadimfrolov.com/farewell-gitlab</guid><category><![CDATA[Design]]></category><category><![CDATA[Cloud]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Sat, 29 Jun 2024 05:57:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1719640551602/4990982b-62b3-454d-a87a-7e13b66242a1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I like to look at different options. Github is not my default go-to solution for git. I used Gitlab, Bitbucket and even bare minimum systems that look like git2web (KDE, NemoMobile).</p>
<p>I have one project at Gitlab that consist of 3 repos. Recently I was not able to push anything to the main one of these repos. It was an internal error 500 related to a re-received hook.</p>
<p>Of course, I tried to research the solution, but the error message lacked any details and error code 500 was very generic. The internet is full of errors 500 for gitlab.</p>
<p>Since I am on a free tier, I can't really complain. It's been working for years, it still does for my other repos. But I find myself in situation when I do not want to spend a week debugging why something broke in some random tech stack.</p>
<p>Luckily, my project is a one-man. I simply moved the code to GitHub. Had to update integrations and deployments, bring on recorded issues. Readthedocs integration still complains, but seem to work.</p>
<p>Thank you Gitlab! Time to check out Github.</p>
]]></content:encoded></item><item><title><![CDATA[Bike locks]]></title><description><![CDATA[Yesterday, the housing cooperative I live in had a spring clean out. This time the goal was to remove all the abandoned bikes. I volunteered to do lock cutting. This was fun! I had a first-time experience cutting locks via a manual bolt cutter like t...]]></description><link>https://blog.vadimfrolov.com/bike-locks</link><guid isPermaLink="true">https://blog.vadimfrolov.com/bike-locks</guid><category><![CDATA[locks]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Tue, 14 May 2024 08:17:08 GMT</pubDate><content:encoded><![CDATA[<p>Yesterday, the housing cooperative I live in had a spring clean out. This time the goal was to remove all the abandoned bikes. I volunteered to do lock cutting. This was fun! I had a first-time experience cutting locks via a manual bolt cutter like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1715673377759/5a80d9a9-7435-4bb2-8d56-2a42cf6893d6.webp" alt class="image--center mx-auto" /></p>
<p>It took me a couple of locks to figure out how to use it properly. Otherwise I could not cut even the thinnest wires. Here is what I can say about bike locks.</p>
<p>Simple locks are super easy to cut even with this manual tool. The only lock I had problems with and didn't cut in the end was U-shape lock:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1715673654445/5ac956b2-b663-485f-8f66-ea0505632c47.webp" alt class="image--center mx-auto" /></p>
<p>Types of locks that were easy to cut:</p>
<h3 id="heading-wire-locks">Wire locks</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1715673730659/13021122-f2c8-469b-b282-505a590f1497.jpeg" alt class="image--center mx-auto" /></p>
<p>Very easy.</p>
<h3 id="heading-chain-locks">Chain locks</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1715674008074/f0bec919-9338-494e-a3d1-bf34a540cea3.jpeg" alt class="image--center mx-auto" /></p>
<p>Pretty easy, but depends on the chain link size.</p>
<h3 id="heading-barrel-locks">'Barrel' locks</h3>
<p>I can't find an image for it. It is similar to wire locks, although the surface of the lock goes into a shape that resembles a series of barrels. It alternates between thicker and thinner parts. These are marginally harder than wire locks. I could not cut all the way through and needed to do a couple of bends by hand to finish the cut.</p>
<h2 id="heading-my-advice">My advice</h2>
<ul>
<li><p>consider the value of your bike and the lock you put on.</p>
</li>
<li><p>have a look at lock reviews on the net.</p>
</li>
<li><p>Do not use wire locks and assume protection!</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[The fun of upgrading hard disk in laptop]]></title><description><![CDATA[I spent last Sunday upgrading the hard disk in my wife's laptop. I went from M.2 SSD 256 Gb to M.2 NVMe 1 Tb drive. I learned about cloning software and figured out that this will be perfect (and easy) since I didn't want to reinstall the OS and all ...]]></description><link>https://blog.vadimfrolov.com/the-fun-of-upgrading-hard-disk-in-laptop</link><guid isPermaLink="true">https://blog.vadimfrolov.com/the-fun-of-upgrading-hard-disk-in-laptop</guid><category><![CDATA[Open Source]]></category><category><![CDATA[Windows]]></category><category><![CDATA[clone]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Tue, 19 Mar 2024 14:05:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1710856655086/bc98ba8d-a1c4-4f0a-8f71-cc086f6616fc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I spent last Sunday upgrading the hard disk in my wife's laptop. I went from M.2 SSD 256 Gb to M.2 NVMe 1 Tb drive. I learned about cloning software and figured out that this will be perfect (and easy) since I didn't want to reinstall the OS and all the apps. Little did I know!</p>
<p>The setup was like this: old drive was inside the laptop, new drive was used via a USB-docking station. The plan was to clone the old drive, put new drive inside the laptop, to enjoy!</p>
<p>The cloning part was very easy! The new drive came from Hynix and they provide a data migration app. The app is not developed by them, but rather it is an OEM version of another cloning software Macrium Reflect produced by company Paramount Software. Anyway, the interface was very straightforward. After 30 minutes or so the new drive looked identical to the older one. It contained 4 partitions: boot, reserved, data, rescue. I went on to swap drives inside the laptop.</p>
<p>Then I booted... into a blue screen! Windows didn't want to boot via the new drive. This opened up the adventure of trying to figure out what was going on. I ended up doing multiple hard drive swaps, multiple cloning attempts. Tried easy fixes via command line, watched videos by Macrium Reflect folks about possible fixtures...</p>
<p>What worked in the end was <a target="_blank" href="https://clonezilla.org/">Clonezilla app</a>. Clonezilla is free and open source software for disk imaging and cloning. I was particularly enjoying how they described the creation of <em>bootable</em> live usb drive with Clonezilla. In my own words:</p>
<p><em>Prepare a media with 500 Mb of free space, unzip this archive and you are good to boot from it.</em></p>
<p>This was such a contrast with Windows which just couldn't boot despite having all the files right there. I wonder what is the actual difference in processing between Clonezilla and Macrium Reflect. Perhaps I will figure it out when I do my next disk upgrade.</p>
]]></content:encoded></item><item><title><![CDATA[[solution] The garage opening app doesn't work]]></title><description><![CDATA[Previously, I showed a screenshot of an app and asked to guess where one has to tap in order to open the garage (https://fralik.hashnode.dev/the-garage-opening-app-doesnt-work). Below I show this area with a green cross.

Tapping anywhere else will h...]]></description><link>https://blog.vadimfrolov.com/solution-the-garage-opening-app-doesnt-work</link><guid isPermaLink="true">https://blog.vadimfrolov.com/solution-the-garage-opening-app-doesnt-work</guid><category><![CDATA[UX]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Fri, 15 Dec 2023 11:54:22 GMT</pubDate><content:encoded><![CDATA[<p>Previously, I showed a screenshot of an app and asked to guess where one has to tap in order to open the garage (<a target="_blank" href="https://fralik.hashnode.dev/the-garage-opening-app-doesnt-work">https://fralik.hashnode.dev/the-garage-opening-app-doesnt-work</a>). Below I show this area with a green cross.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702641053667/86acf5db-414f-4436-a612-d5bc916c775b.png" alt class="image--center mx-auto" /></p>
<p>Tapping anywhere else will have no effect whatsoever.</p>
]]></content:encoded></item><item><title><![CDATA[The garage opening app doesn't work]]></title><description><![CDATA[Have a look at this screenshot of the garage gate opening app. Now, where would you tap to open the gate?]]></description><link>https://blog.vadimfrolov.com/the-garage-opening-app-doesnt-work</link><guid isPermaLink="true">https://blog.vadimfrolov.com/the-garage-opening-app-doesnt-work</guid><category><![CDATA[UX]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Thu, 12 Oct 2023 12:08:46 GMT</pubDate><content:encoded><![CDATA[<p>Have a look at this screenshot of the garage gate opening app. Now, where would you tap to open the gate?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1697112298738/80ca07f3-67b0-4298-b529-b69136cf17d6.jpeg" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Software hallucinations]]></title><description><![CDATA[A lot of people fear large language models (LLM) hallucinations. Well, maybe not fear, but at least discuss it. I wish we were discussing hallucinations of traditional software as well. Like this system that hallucinates that € 0.01 is a discount:]]></description><link>https://blog.vadimfrolov.com/software-hallucinations</link><guid isPermaLink="true">https://blog.vadimfrolov.com/software-hallucinations</guid><category><![CDATA[Bugs and Errors]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Tue, 01 Aug 2023 20:48:56 GMT</pubDate><content:encoded><![CDATA[<p>A lot of people fear large language models (LLM) hallucinations. Well, maybe not fear, but at least discuss it. I wish we were discussing hallucinations of traditional software as well. Like this system that hallucinates that € 0.01 is a discount:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690922770558/b05a8234-8be3-4d60-958a-325cd83266d8.png" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Build on top of existing websites]]></title><description><![CDATA[Some years ago, I blogged about the power of customization. Back then I created a browser plugin to rearrange app icons in Google menu. These were the good old times when Google Reader was still around.
This time I would like to talk about inatur.no....]]></description><link>https://blog.vadimfrolov.com/build-on-top-of-existing-websites</link><guid isPermaLink="true">https://blog.vadimfrolov.com/build-on-top-of-existing-websites</guid><category><![CDATA[customization]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Mon, 31 Jul 2023 08:27:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1690791817957/dd71cda0-263a-4fde-8d54-97d6244864e6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Some years ago, I blogged about the <a target="_blank" href="http://vadimfrolov.blogspot.com/2011/10/power-of-customization.html">power of customization</a>. Back then I created a browser plugin to rearrange app icons in Google menu. These were the good old times when Google Reader was still around.</p>
<p>This time I would like to talk about <a target="_blank" href="https://www.inatur.no">inatur.no</a>. It's a website that allows one to book cabins in Norway (and buy fishing and hunting licenses, but I am mostly interested in cabins in this post). The website has two pages:</p>
<ul>
<li><p>search page where one searches for cabins by date, number of beds, e.t.c.</p>
</li>
<li><p>map page with shows all the cabins on a map.</p>
</li>
</ul>
<p>These two pages are not connected. One can not search on a map page and one can not see cabins on a map after the search. Found cabins are presented as a list. To be fair, it is possible to search by Norwegian administrative districts - there are two drop-downs with names.</p>
<p>I contacted website owners in June 2020 pointing out that it will be helpful to show search results on a map. They replied that this would be indeed a useful feature, something they will consider in the future. Here we are in July 2023 and I built it myself.</p>
<p>From a technical perspective, it was educational to research how inatur is developed. Here are a couple of things I found interesting in no particular order:</p>
<ul>
<li><p>Geo-information is stored in ArcGIS, but it looks like it only contains the bare minimum about the cabins, so one couldn't use it for searching.</p>
</li>
<li><p>Every page with a detailed view of a cabin (<a target="_blank" href="https://www.inatur.no/hytte/60af63e5582e1900032490a4/raudana-del-1-kvennsjoen-ullensvang-fjellstyre">example</a>) contains an image like this</p>
</li>
</ul>
<p><img src="https://s3-eu-north-1.amazonaws.com/geodata-hosting-inatur-prod-files/mapexport/60af63e5582e1900032490a4_mini.jpg" alt class="image--center mx-auto" /></p>
<ul>
<li><p>It is a static image. When clicked - it opens like a popup window with a map that shows that single cabin. There are no coordinates written anywhere on the details page.</p>
</li>
<li><p>The map view shows all the cabins and there is a popup window attached to each of them. It looks like the content of this popup is fetched from an API endpoint on every click.</p>
</li>
</ul>
<h3 id="heading-how-to-show-search-results-on-a-map">How to show search results on a map</h3>
<p>I wanted the functionality to be at hand, so I wanted it to be available online. This means I need some sort of website. One option here is to code everything in javascript: call inatur website and post-process the results. However, this is a no-go as this requires Cross-origin resource sharing (<a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">CORS</a>). Due to security considerations, CORS is generally not allowed on the browser level.</p>
<p>Another option is to fire up a back-end server and do requests from there. So, the back-end will be a proxy between the client and inatur website. This is the route I chose.</p>
<p>I used Azure Functions for hosting. This allows me not to worry about wasted resources when I am not searching for a stay. The processing logic is fairly straightforward:</p>
<ul>
<li><p>obtain a list of cabins with geo-data.</p>
</li>
<li><p>proxy search requests to inatur.</p>
</li>
<li><p>fetch search results and only show the cabins that are present in the search results.</p>
</li>
</ul>
<h3 id="heading-to-conclude">To conclude</h3>
<p>It was a fun little project. Using GitHub Copilot and ChatGPT makes such projects even easier (at least for me as I am not a web developer).</p>
<p>Don't walk away when you think something may be improved. And don't give up if the initial attempt to fix things fails (my email back in 2020).</p>
]]></content:encoded></item><item><title><![CDATA[A case of redesign]]></title><description><![CDATA[Microsoft has Partner Center website that is used for example by app authors who submit apps in Microsoft Store. It's overall design used to include a left vertical navigational panel, an additional panel and the rest went for the main content. Like ...]]></description><link>https://blog.vadimfrolov.com/a-case-of-redesign</link><guid isPermaLink="true">https://blog.vadimfrolov.com/a-case-of-redesign</guid><category><![CDATA[User Interface]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Tue, 03 May 2022 10:34:05 GMT</pubDate><content:encoded><![CDATA[<p>Microsoft has Partner Center website that is used for example by app authors who submit apps in Microsoft Store. It's overall design used to include a left vertical navigational panel, an additional panel and the rest went for the main content. Like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1651564925824/WNj94C4MR.png" alt="Old Partner Center Design" /></p>
<p>The whole thing was redesigned recently. And the main screen looks like a collection of cards which lead to different pages:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1651565175159/XP5IyXNYl.jpg" alt="New Partner Center Design" /></p>
<p>I used to visit this website from my mobile phone a lot. It is a known fact that mobile consumption of internet increased over the past years. So I was really surprised to see this on my screen:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1651565463583/7iF1Fb4bb.jpg" alt="List of apps" /></p>
<p>All the text collapsed to the unreadable state! Yet there is plenty of space below (OK, for someone with 50 apps that won't be the case). The choice of presented information on that screen is also questionable. It shows:</p>
<ol>
<li>product type (app or game) =&gt; not changing often.</li>
<li>Included. I do not know what is this, but it displays the number of addons. I think that it doesn't change too often.</li>
<li>Number of markets (countries) the product is available in =&gt; not changing often.</li>
<li>Base price =&gt; may change.</li>
<li>Status. Whether the app is in the store or not =&gt; may change.</li>
</ol>
<p>To conclude, there are 5 items. I would say that 3 of them do not change often if at all, 2 may change although again not so often.</p>
<p>I think that it makes more sense to use that precious space to present information which is more dynamic hence may have changed since I last opened that page.</p>
<p>And finally one could hide some information when the screen size is small so that user has a chance to consume at least some information.</p>
]]></content:encoded></item><item><title><![CDATA[Improvements (automation) upon police website]]></title><description><![CDATA[I live in Norway and have a residence card, which I have to renew every two years. The process is pretty straightforwad: fill in the application online, book an appointment at the local police station, hand in the documents and get a new card one wee...]]></description><link>https://blog.vadimfrolov.com/automate-udi</link><guid isPermaLink="true">https://blog.vadimfrolov.com/automate-udi</guid><category><![CDATA[automation]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Fri, 23 Oct 2020 15:11:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649430656251/Omhu6L261.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I live in Norway and have a residence card, which I have to renew every two years. The process is pretty straightforwad: fill in the application online, book an appointment at the local police station, hand in the documents and get a new card one week later.</p>
<p>Living in Oslo makes it a bit more challenging. Oslo is the biggest city in Norway. There are many applicants here. Normally I would schedule an appointment something like 3 months in advance. COVID-19 had it's word in this process as well. Recently, when I wanted to renew the residence card, I got a nice error message saying that there are no available appointments at the moment. Not in 3 months, not in 5 months, just none.</p>
<p>But the part that really got me on was the fact that police didn't provide a mechanism, which could notify me about available spots. I would think: OK, if I can not get the appointment now just let me know when I can. I do not know their reasoning for not providing it, so the outcome makes me grumpy.</p>
<p>Technology to the rescue! Last time I did something similar was way back in 2011, when I <a target="_blank" href="http://vadimfrolov.blogspot.com/2011/10/power-of-customization.html">tweaked Google</a> through browser extensions. Let's have a look what is available for us in 2020.</p>
<p>Microsoft has recently released python library <a target="_blank" href="https://github.com/microsoft/playwright">playwright</a>. It allows one to automate browser right from Python. Pretty cool! So I sat down and in 20 minutes had this script:</p>
<pre><code class="lang-python"><span class="hljs-keyword">with</span> sync_playwright() <span class="hljs-keyword">as</span> p:
    browser = p.chromium.launch()
    page = browser.newPage()
    page.goto(<span class="hljs-string">"https://selfservice.udi.no/"</span>)
    page.click(<span class="hljs-string">"#ctl00_BodyRegion_PageRegion_MainRegion_LogInHeading"</span>)

    page.type(<span class="hljs-string">"input[type=email]"</span>, config.EMAIL)
    page.type(<span class="hljs-string">"input[type=password]"</span>, config.PWD.get_secret_value())
    page.click(<span class="hljs-string">"#next"</span>)

    <span class="hljs-keyword">try</span>:
        <span class="hljs-comment"># book appointment</span>
        page.click(<span class="hljs-string">"#ctl00_BodyRegion_PageRegion_MainRegion_IconNavigationTile2_heading"</span>)
    <span class="hljs-keyword">except</span> playwright.helper.TimeoutError:
        msg = <span class="hljs-string">"Failed to login. Check your password."</span>
        print(msg)
        telegram_send.send(messages=[msg])
        <span class="hljs-keyword">return</span>

    <span class="hljs-comment"># click on the first one in the list</span>
    page.click(
        <span class="hljs-string">"#ctl00_BodyRegion_PageRegion_MainRegion_ApplicationOverview_applicationOverviewListView_ctrl0_btnBookAppointment"</span>
    )

    <span class="hljs-keyword">try</span>:
        page.waitForSelector(
            <span class="hljs-string">"#ctl00_PageRegion_MainContentRegion_ViewControl_spnReceiptAndBooking_divErrorMessageForNoAvailabelAppointments"</span>,
            timeout=<span class="hljs-number">5000</span>,
        )
        <span class="hljs-comment"># No appointments</span>
        print(<span class="hljs-string">"No appointments"</span>)
        <span class="hljs-keyword">return</span>
    <span class="hljs-keyword">except</span> playwright.helper.TimeoutError:
        msg = <span class="hljs-string">"Looks like UDI is ready for appointments"</span>
        telegram_send.send(messages=[msg])

        <span class="hljs-keyword">with</span> tempfile.TemporaryFile(<span class="hljs-string">"r+b"</span>) <span class="hljs-keyword">as</span> fp:
            encoded_img = page.screenshot(type=<span class="hljs-string">"png"</span>)
            fp.write(encoded_img)
            fp.seek(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>)
            telegram_send.send(images=[fp])
</code></pre>
<p>It logs in as you at the police website, then opens the very first of your applications and checks for presence of an error message (the error message saying that there are no available appointments). If there is no error message, then it sends a message and a screenshot of the page to my Telegram bot. Runing this script from a cron job I do not need to check the website manually. Sweet!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649430696434/xruumXURE.png" alt="telega" /></p>
<p>This type of activity leaves me with mixed feelings. I very much enjoy that I can do something useful, and stitch together a solution, and extend something. On the other hand side, shall I spend my life fixing this type of things?! Shouldn't this functionality be there right from the beginning?</p>
<p>PS. Grab the code from Github repo <a target="_blank" href="https://github.com/fralik/udiinformer">udiinformer</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Using VCR.py with MSAL]]></title><description><![CDATA[Once upon a time I decided to write some integration tests with help of VCR.py. VCR.py simplifies and speeds up tests that make HTTP requests. It records all HTTP interactions in a cassette file. When you run the same code again, it will replay all H...]]></description><link>https://blog.vadimfrolov.com/using-vcrpy-with-msal</link><guid isPermaLink="true">https://blog.vadimfrolov.com/using-vcrpy-with-msal</guid><category><![CDATA[Python]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Thu, 08 Oct 2020 15:09:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649430552406/0jk5AKvug.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Once upon a time I decided to write some integration tests with help of <a target="_blank" href="https://vcrpy.readthedocs.io/en/latest/">VCR.py</a>. VCR.py simplifies and speeds up tests that make HTTP requests. It records all HTTP interactions in a cassette file. When you run the same code again, it will replay all HTTP interactions from a cassette file. Sounds great for writing tests! Little did I know.</p>
<p>My HTTP requests involved authentication to Azure AD. I am using <a target="_blank" href="https://github.com/AzureAD/microsoft-authentication-library-for-python">MSAL</a> library. By the time I started with VCR, I have already spent some time trying to authenticate in an easy-for-user manner. In the end, integrated windows authentication beat me hard requiring two factor authentication. I felt frustrated, but at the same time happy that running <code>tox</code> resulted in all green colors. Until I committed the code and then run the tests some time later.</p>
<p>Oh, ah! What's going on?!</p>
<pre><code class="lang-python">======== short test summary info =========
FAILED test_application.py::TestApplication::test_application_list - AssertionError: The command failed. Exit code: <span class="hljs-number">1</span>
======== <span class="hljs-number">1</span> failed <span class="hljs-keyword">in</span> <span class="hljs-number">6.67</span>s ===============
ERROR: InvocationError <span class="hljs-keyword">for</span> command <span class="hljs-string">'C:\some\.tox\py37\Scripts\pytest.EXE'</span> test_application.py --junitxml=.tox/junit.py37.xml (exited <span class="hljs-keyword">with</span> code <span class="hljs-number">1</span>)
______ summary ___________________________
ERROR:   py37: commands failed
</code></pre>
<p>There was an actual error message <code>9. The current time MUST be before the time represented by the exp Claim. id_token was</code>. It gave me a hint, but since I normally do not deal with authentication on a low level, I spent some time trying various things.</p>
<p>To spare your time, here is a recipe. The problem was in <code>id_token</code> saved in HTTP response. <code>id_token</code> is a string like this</p>
<pre><code><span class="hljs-attribute">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9</span>.eyJsb<span class="hljs-number">2</span>dnZWRJbkFzIjoiYWRtaW<span class="hljs-number">4</span>iLCJpYXQiOjE<span class="hljs-number">0</span>MjI<span class="hljs-number">3</span>Nzk<span class="hljs-number">2</span>Mzh<span class="hljs-number">9</span>.gzSraSYS<span class="hljs-number">8</span>EXBxLN_oWnFSRgCzcmJmMjLiuyu<span class="hljs-number">5</span>CSpyHI
</code></pre><p>This is a <a target="_blank" href="https://en.wikipedia.org/wiki/JSON_Web_Token">JWT token</a>, consisting of 3 parts separated by <code>.</code> character. The decoded data contains expiration date, which of course is in the past for a pre-recorded interaction.</p>
<p>Since I am in Python, I studied the code of MSAL library that deals with the token and found out that it only decodes the payload part (at least in the function that fails). My wild attempt would be to adjust expiration time, create a new token based on the current one and hope that MSAL will accept it.</p>
<p>Here is the code that does just that</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> time
<span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> base64
<span class="hljs-keyword">from</span> msal.oauth2cli.oidc <span class="hljs-keyword">import</span> decode_part


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">adjust_token_time</span>(<span class="hljs-params">id_token: str</span>) -&gt; str:</span>
    header_enc = id_token.split(<span class="hljs-string">'.'</span>)[<span class="hljs-number">0</span>]
    payload = json.loads(decode_part(id_token.split(<span class="hljs-string">'.'</span>)[<span class="hljs-number">1</span>]))
    signature_enc = id_token.split(<span class="hljs-string">'.'</span>)[<span class="hljs-number">2</span>]

    payload[<span class="hljs-string">"exp"</span>] = round(time.time() + <span class="hljs-number">80</span>)  <span class="hljs-comment"># seconds</span>
    payload = json.dumps(payload).encode(<span class="hljs-string">"utf-8"</span>)

    paylod_enc = base64.urlsafe_b64encode(payload).decode().strip(<span class="hljs-string">'='</span>)
    token = <span class="hljs-string">"."</span>.join([header_enc, paylod_enc, signature_enc])
    <span class="hljs-keyword">return</span> token
</code></pre>
<p>New expiration time must not exceed 2 minutes. Otherwise one gets a different MSAL error. You can see that my new token is a very dirty forgery. Nevertheless it works and I am happy for now.</p>
<p>This function must be executed as part of pre-processing when VCR.py plays the cassette.</p>
]]></content:encoded></item><item><title><![CDATA[Quest for a compact smartphone in 2020]]></title><description><![CDATA[Getting an android phone in compact form factor with decent specs is mission impossible. My current phone is Sony Xperia X Compact, which was great at time of purchase. Especially in terms of size. One of my colleagues uses X Compact. And he has anot...]]></description><link>https://blog.vadimfrolov.com/quest-for-a-compact-smartphone-in-2020</link><guid isPermaLink="true">https://blog.vadimfrolov.com/quest-for-a-compact-smartphone-in-2020</guid><category><![CDATA[user experience]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Sun, 20 Sep 2020 15:07:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649430445906/yyG6GVV2e.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Getting an android phone in compact form factor with decent specs is mission impossible. My current phone is <a target="_blank" href="https://www.gsmarena.com/sony_xperia_x_compact-8292.php">Sony Xperia X Compact</a>, which was great at time of purchase. Especially in terms of size. One of my colleagues uses X Compact. And he has another one still packed laying in a closet for the time when his current one dies. X Compact is still great, but I suffer from a couple of things. I rooted my phone and can't use corporate accounts and some payment apps. It is annoying, but I actually value my root access more. The second issue is a bit unconfirmed, but looks suspicious. I used to use my phone as part of a medical device. However, it's seems that it has some issues on hardware level. Issues are occasional, hard to track, but I am willing to try another phone, which hopefully won't have these issues.</p>
<p>Mind you this post doesn't contain thorough analysis of markets, revenue, e.t.c. This is a psychoanalysis post!</p>
<p>A brief comment about rooting. This is so post-truth. I can use banking apps without an issue, but not payment apps. And I get notifications at boot time that my phone can not be trusted. Seriously, I trust my phone more after I've unlocked the bootloader and gained root access. </p>
<p>My ideal phone would be <a target="_blank" href="https://en.wikipedia.org/wiki/Nokia_N900">Nokia N900</a> with modern hardware. N900 has Linux-based OS, nice almost full size keyboard and touch interface. What else do we need?!</p>
<p>Modern smartphones. We call them <em>shovels</em> in Russian: [ɫɔpata] or lopáta. I reckon because their best usage is to attach a handle, dig a grave and bury the common sense in it. Don't get me wrong, I am OK with big phones. I am not OK with a lack of decent small phones.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649430266563/H3lUmgWLm.png" alt="shovel" /></p>
<p>It's funny how trends emerge (whatever this is). We are still in the "let's make it thinner" trend, which expanded to laptops as well. <em>Our phone is 150 m long, but you know what, it is just 0.15 mm thin, which is 0.003 mm thinner then any other phone. This is awesome!</em> And because we want our phones to be thin, let's make non-removable battery!</p>
<p>I used to have a phone known as Highscreen Boost in Russia, which is a rebranded Chinese one. It was 4", had dimensions of 124×65×15 mm and had a crazy 4160 mAh battery (GSMArena doesn't even aware of it's existence). Most of the phone was the battery. Despite it's 15 mm thickness it was very usable. And it could not slip out of hands.</p>
<p><img src="https://www.ixbt.com/mobile/images/highscreen-boost/boost1.jpg" alt="boost" /></p>
<p>Back to the present day. Last year I was hoping that Sony would come with a new compact during MWC 2020. First, the event was canceled due to corona. Then, the Sony came out with new design, which for me means <em>we have to be different somehow, but we do not know how</em>. Too bad.</p>
<p>Faced with the problem of getting a new phone I went and made a spreadsheet with specs of some models that looked interesting.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649430300324/3VZnymoxS.png" alt="specs" /></p>
<p>Since I am obsessed with size, I decided to make some dummy phones to test them in the wild. As a bonus it was enough entertainment for a morning with 3.5 years old.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649430358694/0HBG6jYcl.jpg" alt="dummies" /></p>
<p>As contesters we have:</p>
<ol>
<li>a real shovel with generic model that corresponds to Cat S62 Pro or Sony Xperia XZ Premium. Dunno how they came to short list. I guess I just wanted to try out a big one.</li>
<li>Yet to be released Sony Xperia 5 II (with a nice Spotify app running).</li>
<li>Samsung Galaxy S10e and Pixel 4a.</li>
</ol>
<p>By trying these models in real life, it quickly turned out that Galaxy and Pixel form factor is the most suitable for me. Which one to choose? Samsung comes full of bloatware, Pixel is cleaner in this regard. So perhaps Google (although I am not their big fan). Or I just keep using my current phone and come with another rant in one year.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649430422664/GrJ6-2UaR.JPG" alt="DSC_6558.JPG" />
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649430425968/lkWt0XEiU.jpg" alt="all" /></p>
]]></content:encoded></item><item><title><![CDATA[Ads in free internet services]]></title><description><![CDATA[You think Google is evil with their ads? Russia took ads on a new level.
Some internet pages are blocked in Russia. If you try to access them, you'll end up on a landing page of your internet provider. And guess what you will see on such page. Right,...]]></description><link>https://blog.vadimfrolov.com/ads-in-free-internet-services</link><guid isPermaLink="true">https://blog.vadimfrolov.com/ads-in-free-internet-services</guid><category><![CDATA[user experience]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Thu, 26 Dec 2019 16:02:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649429952244/MO6-YJ0Mj.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You think Google is evil with their ads? Russia took ads on a new level.</p>
<p>Some internet pages are blocked in Russia. If you try to access them, you'll end up on a landing page of your internet provider. And guess what you will see on such page. Right, ads.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649429952244/MO6-YJ0Mj.jpg" alt="blocked_ads" /></p>
<p>In web e-mail from Yandex ads are turned on by default:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649430025409/RjkLgmbh6.JPG" alt="web_ads" /></p>
<p>However, there is a setting to turn it off:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649430071506/q5F0GOEcv.JPG" alt="web_ads_settings" /></p>
<p>And interestingly enough there are no ads and no setting if one switches language interface to English.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649430109401/_8K5O3X8k.png" alt="webmaulenglishsettings" /></p>
<p>Another popular Russian product Yandex.Navi. Navi is a turn-by-turn navigation app. Yandex offers rich set of assistant voices. I found one particularly funny, it's label was "Whitecat Gourmet". It is actually cool to have such things as they make computer systems less dull. </p>
<p>Anyway, this voice have been produced in a great cooperation between Yandex and... well whitecat Gourmet company. Some other voices were of a similar nature. I think you do not hear any ads while driving, but all voices have a short intro, which is played when you select it.</p>
]]></content:encoded></item><item><title><![CDATA[Yandex Drive car sharing usability]]></title><description><![CDATA[Whenever someone suggests to make an input for a phone number with pre-defined number, stand up and oppose! Computers are for humans, not the other way around.

Yandex Drive wants a number with 10 digits. 

Ok, my Norwegian number has 10 digits. Nope...]]></description><link>https://blog.vadimfrolov.com/yandex-drive-car-sharing-usability</link><guid isPermaLink="true">https://blog.vadimfrolov.com/yandex-drive-car-sharing-usability</guid><category><![CDATA[user experience]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Thu, 26 Dec 2019 15:56:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649429768429/RUTtnkpfa.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Whenever someone suggests to make an input for a phone number with pre-defined number, stand up and oppose! Computers are for humans, not the other way around.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649429768429/RUTtnkpfa.png" alt="Screenshot_20191226-101432.png" /></p>
<p>Yandex Drive wants a number with 10 digits. 
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649429785211/xSxosJrqO.png" alt="Screenshot_20191226-100802.png" /></p>
<p>Ok, my Norwegian number has 10 digits. Nope, it's not valid and they won't tell me what is the problem. On the other hand, Yandex Drive is a service in Russia. My Russian number has 11 digits in it. Bummer! </p>
]]></content:encoded></item><item><title><![CDATA[Activation of conda environments from Far Manager]]></title><description><![CDATA[I've switched back to Windows on work recently. Turned out I am too attached to Far Manager(these days Far is even greater with ConEmu). If you are a developer on Windows and you do not know about this stuff, go check it out. It is fantastic. Scott H...]]></description><link>https://blog.vadimfrolov.com/activation-of-conda-environments-from-far-manager</link><guid isPermaLink="true">https://blog.vadimfrolov.com/activation-of-conda-environments-from-far-manager</guid><category><![CDATA[Python]]></category><dc:creator><![CDATA[Vadim Frolov]]></dc:creator><pubDate>Sat, 27 Apr 2019 14:54:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1649429639142/kTTxsaHhI.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I've switched back to Windows on work recently. Turned out I am too attached to <a target="_blank" href="https://www.farmanager.com/">Far Manager</a>(these days Far is even greater with <a target="_blank" href="https://conemu.github.io/">ConEmu</a>). If you are a developer on Windows and you do not know about this stuff, go check it out. It is fantastic. Scott Hanselman has a nice <a target="_blank" href="https://www.hanselman.com/blog/ConEmuTheWindowsTerminalConsolePromptWeveBeenWaitingFor.aspx">post</a> about it.</p>
<p>I am also more into python development these days. Which (for me) means usage of conda and it's environments. Anaconda developers suggest that on Windows one should start a special <em>Anaconda Propmt</em>. I would like to be able to activate environments straight from Far. Sounds easy: just be sure to be able to run conda. However once I do</p>
<pre><code class="lang-shell">conda activate new-env
cona env list
</code></pre>
<p>I observe that environment has not been changed. Environment activation is basically a modification of environment variables.
Here is how it looks like:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649429582239/Mvo9hqbdf.gif" alt="conda_not_working.gif" /></p>
<p>The reason for such behavior is that Far spans a new CMD process for every command. So in our case <code>conda activate new-env</code> will be a new process, which will modify environment variable, but these changes will die once process is ended.</p>
<p><a target="_blank" href="https://plugring.farmanager.com/plugin.php?pid=823&amp;l=en">FarCall</a> plugin for the rescue. This plugin allows one to call a batch file and imports environment variables to Far process. Neat. Once you have the plugin in place, you can activate the environment like this:</p>
<pre><code class="lang-bash">call:conda activate new-env
</code></pre>
<p>Note that this won't change the command propmpt. But we can fix this too. I did it through Far Manager settings for the command propmpt (<code>Options -&gt; Command line settings -&gt; Set command line prompt format</code>). <em>Set the value to</em> (see <strong>UPDATE 2</strong> about it):</p>
<pre><code class="lang-bash">%CONDA_PROMPT_MODIFIER%<span class="hljs-variable">$p</span><span class="hljs-variable">$g</span>
</code></pre>
<p>And the last bit to it, you actually have to go and create a user-scoped environment variable <code>CONDA_PROMPT_MODIFIER</code> and make it non-empty. I assigned it a single space. I observed that empty <code>CONDA_PROMPT_MODIFIER</code> will result in command propmpt that will print the name of the environment variable instead of printing nothing.</p>
<p>Here is the result:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649429617338/EkBKonF0D.gif" alt="conda_working-1.gif" /></p>
<p>Happy coding!
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649429625530/ElEh4_zSP.png" alt="farconda-1.png" /></p>
<p><strong>UPDATE</strong>
This won't work with deactivation. During deactivation conda's script does things like this:</p>
<pre><code><span class="hljs-variable">@SET</span> CONDA_PREFIX=
<span class="hljs-variable">@SET</span> CONDA_DEFAULT_ENV=
<span class="hljs-variable">@SET</span> CONDA_PROMPT_MODIFIER=
</code></pre><p>which besically removes environment variables. When it is time for FarCall to enumerate environment variables, there are no <code>CONDA_PROMPT_MODIFIER</code>, so FarCall does not propagate the empty value (or reset). Sigh!</p>
<p><strong>UPDATE 2</strong>
Somehow I overlooked that one can use <code>PROMPT</code> environment variable instead of <code>CONDA_PROMPT_MODIFIER</code>. It is better because then Far will work nicely not only with conda, but with Pipenv (in case you use it). So define an environment variable <code>PROMPT</code> and set command line format in Far to <code>%PROMPT%</code>. My default value for <code>PROMPT</code> is <code>$p$g</code>.</p>
]]></content:encoded></item></channel></rss>