{
    "version": "https:\/\/jsonfeed.org\/version\/1.1",
    "title": "Блоги: заметки с тегом programming",
    "_rss_description": "Автоматически собираемая лента заметок, написанных в блогах на Эгее",
    "_rss_language": "ru",
    "_itunes_email": "",
    "_itunes_categories_xml": "",
    "_itunes_image": false,
    "_itunes_explicit": "no",
    "home_page_url": "https:\/\/blogengine.me\/blogs\/tags\/programming\/",
    "feed_url": "https:\/\/blogengine.me\/blogs\/tags\/programming\/json\/",
    "icon": false,
    "authors": [
        {
            "name": "Илья Бирман",
            "url": "https:\/\/blogengine.me\/blogs\/",
            "avatar": false
        }
    ],
    "items": [
        {
            "id": "133971",
            "url": "https:\/\/robertblinov.net\/blog\/all\/cybersecurity\/",
            "title": "Technological measures for cybersecurity",
            "content_html": "<p>There are various kinds of cybersecurity measures: organisational, legal, technological, and physical. All of them are useful, but the technological ones are the most resilient.<\/p>\n<h2>Policies and platforms are short-lived by nature<\/h2>\n<p>Legislation and policies are short-lived and unreliable, they are easy to bypass and modify. Just as platforms, they are created and maintained in a centralised manner by people who cannot be held to account. Protocols, on the other hand, are far more reliable, because they work in any jurisdiction and under any management. If a protocol’s creator dies or loses control, it keeps on working regardless. SimpleX, RSS, Monero, and the internet itself are all open protocols that do not belong to any company.<\/p>\n<p>There can be any formal rule, but only the technologically enforced one will be followed. To falsify a contract on a Proof-of-Work blockchain, one needs to take over 51% of the network, and not just a single notary office. Good cryptocurrencies have monetary policies that are deeply thought through, so people don’t have to worry about central banks making the “right choice”. Decentralised domain protocols allow for true domain ownership, so people don’t have to worry about the benevolence of the Internet Corporation for Assigned Names and Numbers (ICANN).<\/p>\n<p>As for data protection, it’s possible, of course, to open a company in one country and have it belong to two legal entities in two other countries, dividing data between different jurisdictions. Yet legislation can always change, while technologies will keep on working regardless. Such a legal move can only be an addition to technological measures, not their replacement.<\/p>\n<p>The European GDPR allows citizens to withdraw consent to their data being processed, as well as to exercise “the right to be forgotten” and thereby remove all data about themselves from the public eye. But as the Streisand effect proves, a person who states the desire to hide will thereafter only become more visible. Services that truly want to streamline data deletion allow it to be done with a simple click — no emails and phone calls required.<\/p>\n<p>“Security through obscurity” leads to lack of responsibility and accountability. Good defence works even if the enemy knows how it works.<\/p>\n<h2>The zero-trust approach works best<\/h2>\n<p>When a system is transparent and comprehensible, there is no need to rely on others’ oaths: violations are seen, while vulnerabilities are easy to fix. Transparent and comprehensible software is open-source, its builds are reproducible. If it connects to the web, it has an <a href=\"https:\/\/obdev.at\/iap\/index.html\">Internet Access Policy<\/a>.<\/p>\n<p>Reliable devices have open schematics and, when possible, are physically transparent to make it easy to notice foreign components. The microphone and camera are turned off electrically, not via software.<\/p>\n<p>If some code isn’t being used, it needs to be removed. The simpler the software, the fewer the bugs & vulnerabilities, and the higher the likelihood of detailed external audits.<\/p>\n<p>Technologies should be built in ways that make surveillance impossible, with data being processed only after the user’s conscious consent. It’s preferable for all new technologies to be backwards-compatible: this makes their adoption easier. Optional privacy is no privacy at all, as it divides people into normies and “those with something to hide” — that’s why Monero rules and Zcash drools.<\/p>\n<p>The zero-trust model is a good way to enhance security. In an organisation, this means embedding multi-level access control: each person can only access the data needed for the time needed. Accepting that anything can leak leads to minimising data collection and storage; accounts are not created without good reason.<\/p>\n<p>Zero-trust can also be implemented on a local level via sandboxing. This means isolating browsers, ecosystems, and devices: using one for the personal, another for work, and a third for the alter ego. Access to one account or device will thus never be enough to paint a full picture of someone’s life.<\/p>\n<h2>Tips to enhance privacy and security<\/h2>\n<p>As many interactions as possible should happen anonymously or at least pseudonymously. To make identification more difficult, one can reduce the amount of static data by constantly changing IP addresses with a VPN, randomising MAC addresses, <a href=\"https:\/\/youtu.be\/Vt4Jl4t43ug\">preferring IPv4 to IPv6<\/a>, spreading disinformation about identity. It’s harder to identify a person whose name isn’t tied to a device.<\/p>\n<p>Browser-level protection is not enough: it’s not the only program communicating with the internet. Also, the more a browser is configured, such as with installed plugins, the easier it is to identify the person through metadata. Restrictions, such as those related to scripts, should be set on the system or router level.<\/p>\n<p>Authentication should consist of multiple factors: what a person knows and what a person has. Emails and SMS messages should not be obligatory factors because of their low privacy. There also should not be any shared secrets: many people are unable to follow instructions and keep passwords in a safe place.<\/p>\n<p>As much as possible should happen locally: the cloud is just someone else’s computer, while trusted third parties are security holes. However, if an interaction requires the internet, a web app is safer than a local app: a closed browser tab guarantees absence of background communications.<\/p>\n<p>Almost everything should be encrypted, but it’s important to remember that malware (and on-device AI) can gather data before encryption and after decryption.<\/p>\n<p>It’s best to avoid passing SSDs onto others: the only way to truly ensure the absence of previously “deleted” data is to smash the disk.<\/p>\n<p>To completely exclude remote attacks, a device should not have Wi-Fi, Bluetooth, microphones, and cameras; any connections should happen physically. Such devices are typically kept in hard-to-reach places. If such a device were to be accessed, it should notify about this, both on the software and hardware levels. The most advanced devices use deniable encryption, fooling potential extorters into believing that the little data they manage to retrieve is all there is.<\/p>\n<h2>Final thoughts<\/h2>\n<p>Certain kinds of digital threats can be prevented only with transparent technological measures.<\/p>\n<p>However, a system can never be fully secure — this would make it inoperable. Tradeoffs are unavoidable; security measures should be chosen based on threat model, threat probability, objective limitations, long-term goals, and budget.<\/p>\n<p>As of today, network effects continue to sway people towards centralised messaging apps, many sites needlessly require registration, hardly any devices have open schematics, and decentralised domain protocols are still uncommon. There is great room for improvement — let’s get to it.<\/p>\n",
            "date_published": "2024-07-29T13:11:19+05:00",
            "date_modified": "2025-08-27T17:20:53+05:00",
            "tags": [
                "decentralisation",
                "Europe",
                "legislation",
                "privacy",
                "programming",
                "software",
                "solutions",
                "strategy",
                "tech",
                "websteads"
            ],
            "author": {
                "name": "Robert",
                "url": "https:\/\/robertblinov.net\/blog\/",
                "avatar": "https:\/\/robertblinov.net\/blog\/pictures\/userpic\/userpic@2x.jpg?1739870896"
            },
            "_date_published_rfc2822": "Mon, 29 Jul 2024 13:11:19 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "133971",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "126033",
            "url": "https:\/\/dsokolovskiy.com\/blog\/all\/scrabble-in-c\/",
            "title": "Scrabble in C",
            "content_html": "<p>In the second week of <a href=\"\/blog\/tags\/cs50\/\">CS50<\/a>, I was introduced to the notion of arrays and then given the following problem to solve as a practice:<\/p>\n<div class=\"question\"><p>In the game of <a href=\"https:\/\/www.scrabblepages.com\/scrabble\/rules\/\">Scrabble<\/a>, players create words to score points, and the number of points is the sum of the point values of each letter in the word. For example, if we wanted to score the word “CODE”, we would note that the ‘C’ is worth 3 points, the ‘O’ is worth 1 point, the ‘D’ is worth 2 points, and the ‘E’ is worth 1 point. Summing these, we get that “CODE” is worth 7 points.<\/p>\n<p>Implement a program in C that determines the winner of a short Scrabble-like game. Your program should prompt for input twice: once for “Player 1” to input their word and once for “Player 2” to input their word. Then, depending on which player scores the most points, your program should either print “Player 1 wins!”, “Player 2 wins!”, or “Tie!” (in the event the two players score equal points).<\/p>\n<\/div><p>First, I outlined the general steps needed to solve this problem:<\/p>\n<ol start=\"1\">\n<li>Get text inputs from the user;<\/li>\n<li>Calculate the score of each input;<\/li>\n<li>Show the winner.<\/li>\n<\/ol>\n<p>For the first step, I’ll creat two variables named <i>word1<\/i> and <i>word2<\/i> respectively, and assign each to the value of the respective user input using the <i>get_string<\/i> function from the CS50 library:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">#include &lt;cs50.h&gt;\r\n#include &lt;stdio.h&gt;\r\n#include &lt;string.h&gt;\r\n\r\nint main(void)\r\n{\r\n    \/\/ Prompt the user for two words\r\n    string word1 = get_string(&quot;Player 1: &quot;);\r\n    string word2 = get_string(&quot;Player 2: &quot;);\r\n\r\n    \/\/ Compute the score of each word\r\n\r\n    \/\/ Print the winner\r\n}<\/code><\/pre><p>That was easy. The trickiest part here, of course, is the second step, which is to assign each letter of the alphabet its unique score points value.<\/p>\n<p>Here are the values:<\/p>\n<div class=\"e2-text-table\">\n<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n<tr>\n<td style=\"text-align: center\">A<\/td>\n<td style=\"text-align: center\">B<\/td>\n<td style=\"text-align: center\">C<\/td>\n<td style=\"text-align: center\">D<\/td>\n<td style=\"text-align: center\">E<\/td>\n<td style=\"text-align: center\">F<\/td>\n<td style=\"text-align: center\">G<\/td>\n<td style=\"text-align: center\">H<\/td>\n<td style=\"text-align: center\">I<\/td>\n<td style=\"text-align: center\">J<\/td>\n<td style=\"text-align: center\">K<\/td>\n<td style=\"text-align: center\">L<\/td>\n<td style=\"text-align: center\">M<\/td>\n<td style=\"text-align: center\">N<\/td>\n<td style=\"text-align: center\">O<\/td>\n<td style=\"text-align: center\">P<\/td>\n<td style=\"text-align: center\">Q<\/td>\n<td style=\"text-align: center\">R<\/td>\n<td style=\"text-align: center\">S<\/td>\n<td style=\"text-align: center\">T<\/td>\n<td style=\"text-align: center\">U<\/td>\n<td style=\"text-align: center\">V<\/td>\n<td style=\"text-align: center\">W<\/td>\n<td style=\"text-align: center\">X<\/td>\n<td style=\"text-align: center\">Y<\/td>\n<td style=\"text-align: center\">Z<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">3<\/td>\n<td style=\"text-align: center\">3<\/td>\n<td style=\"text-align: center\">2<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">4<\/td>\n<td style=\"text-align: center\">2<\/td>\n<td style=\"text-align: center\">4<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">8<\/td>\n<td style=\"text-align: center\">5<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">3<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">3<\/td>\n<td style=\"text-align: center\">10<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">4<\/td>\n<td style=\"text-align: center\">4<\/td>\n<td style=\"text-align: center\">8<\/td>\n<td style=\"text-align: center\">4<\/td>\n<td style=\"text-align: center\">10<\/td>\n<\/tr>\n<\/table>\n<\/div>\n<p>Now that I know about arrays, I can create an array called <i>points<\/i> with a size of 26 and the type of integer, and assign values as follows:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">#include &lt;cs50.h&gt;\r\n#include &lt;stdio.h&gt;\r\n#include &lt;string.h&gt;\r\n\r\nint main(void)\r\n{\r\n    \/\/ Prompt the user for two words\r\n    string word1 = get_string(&quot;Player 1: &quot;);\r\n    string word2 = get_string(&quot;Player 2: &quot;);\r\n\r\n    \/\/ Compute the score of each word\r\n    int points[] = {1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1, 3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10};\r\n\r\n    \/\/ Print the winner\r\n}<\/code><\/pre><p>I don’t quite like the length of that like, but it seems there is not much to do about it since all values are set by the rules of the game.<\/p>\n<p>Now that I know a little bit about functions too, I’ll create a separate function for computing the score. This should make the code more efficient and better designed, especially since I need to use it twice for calculating the score for each word.<\/p>\n<p>I’ll call this function <i>calculate_score<\/i>, with one input parameter of the type of string, and output of integer. I can also straight away create a variable called <i>score<\/i> with the type of integer, as this is ultimately what I want to get from this function:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">int calculate_score(string word)\r\n{\r\n    int score = 0;\r\n\r\n    return score;\r\n}<\/code><\/pre><p>Now, the big question is how to assign each letter a corresponding score value. Well, turns out that every string is basically just an array of characters. Let’s take the word CODE as an example. We can imagine it as an array as follows, keeping in mind the zero-based indexing of arrays, i.e. starting counting from 0:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">c word[i]\r\nword[0] = C\r\nword[1] = O\r\nword[2] = D\r\nword[3] = E<\/code><\/pre><p>Knowing this, I can create a loop to ‘scan’ through the word character by character. For this loop to work, I would to know the length of the word, and luckily such a function already exists in the <i>string.h<\/i> library and is called <i>strlen<\/i>:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">for (int i = 0; i &lt; strlen(word); i++)\r\n{\r\n}<\/code><\/pre><p>What I don’t quite like about this loop though, is that every time it works, it makes the function repeat that many times. To optimise this, let me create another variable called <i>len<\/i> with its value equal to the length of a word, and then use this variable as the condition of the loop:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">for (int i = 0, len = strlen(word); i &lt; len; i++)\r\n{\r\n}<\/code><\/pre><p>Now, how to make the loop ‘know’ which score value corresponds to each letter? There is actually a trick that still blows my mind even after completing this task. Since every character has its numeric value in the <a href=\"https:\/\/www.w3schools.com\/charsets\/ref_html_ascii.asp\">ASCII code<\/a>, we can use this information to ‘offset’ characters from one array to another and this way map them together.<\/p>\n<p>Let’s take the capital letter ‘C’ from the word CODE as I used the example. Its numeric value in ASCII is 67, and the trick is to subtract the value of the letter A, which equals 65. Why A? Because it’s the first letter of the alphabet, and if we subtract it from another letter, we’ll know its place in the array. So <i>67 – 65 = 2<\/i>, and that is exactly the index number we need from the <i>points<\/i> array.<\/p>\n<p>To make it more visual, here is a similar exercise for all letters of the word CODE:<\/p>\n<div class=\"e2-text-table\">\n<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n<tr>\n<td style=\"text-align: center\">Letter<\/td>\n<td style=\"text-align: center\">ASCII<\/td>\n<td style=\"text-align: left\">Index<\/td>\n<td style=\"text-align: right\">Points<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: center\">C<\/td>\n<td style=\"text-align: center\">67<\/td>\n<td style=\"text-align: left\">67 – 65 = [2]<\/td>\n<td style=\"text-align: center\">3<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: center\">O<\/td>\n<td style=\"text-align: center\">79<\/td>\n<td style=\"text-align: left\">79 – 65 = [14]<\/td>\n<td style=\"text-align: center\">1<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: center\">D<\/td>\n<td style=\"text-align: center\">68<\/td>\n<td style=\"text-align: left\">68 – 65 = [3]<\/td>\n<td style=\"text-align: center\">2<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: center\">E<\/td>\n<td style=\"text-align: center\">69<\/td>\n<td style=\"text-align: left\">69 – 65 = [4]<\/td>\n<td style=\"text-align: center\">1<\/td>\n<\/tr>\n<\/table>\n<\/div>\n<p>... which means the word CODE gives the Scrabble score of 7 (as 3 + 1 + 2 +1), and that is indeed correct. It works like a charm!<\/p>\n<p>To make array indexing a little more obvious, I’ll add it to the score table too:<\/p>\n<div class=\"e2-text-table\">\n<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n<tr>\n<td>Letter:<\/td>\n<td style=\"text-align: center\">A<\/td>\n<td style=\"text-align: center\">B<\/td>\n<td style=\"text-align: center\">C<\/td>\n<td style=\"text-align: center\">D<\/td>\n<td style=\"text-align: center\">E<\/td>\n<td style=\"text-align: center\">F<\/td>\n<td style=\"text-align: center\">G<\/td>\n<td style=\"text-align: center\">H<\/td>\n<td style=\"text-align: center\">I<\/td>\n<td style=\"text-align: center\">J<\/td>\n<td style=\"text-align: center\">K<\/td>\n<td style=\"text-align: center\">L<\/td>\n<td style=\"text-align: center\">M<\/td>\n<td style=\"text-align: center\">N<\/td>\n<td style=\"text-align: center\">O<\/td>\n<td style=\"text-align: center\">P<\/td>\n<td style=\"text-align: center\">Q<\/td>\n<td style=\"text-align: center\">R<\/td>\n<td style=\"text-align: center\">S<\/td>\n<td style=\"text-align: center\">T<\/td>\n<td style=\"text-align: center\">U<\/td>\n<td style=\"text-align: center\">V<\/td>\n<td style=\"text-align: center\">W<\/td>\n<td style=\"text-align: center\">X<\/td>\n<td style=\"text-align: center\">Y<\/td>\n<td style=\"text-align: center\">Z<\/td>\n<\/tr>\n<tr>\n<td>Score:<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">3<\/td>\n<td style=\"text-align: center\">3<\/td>\n<td style=\"text-align: center\">2<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">4<\/td>\n<td style=\"text-align: center\">2<\/td>\n<td style=\"text-align: center\">4<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">8<\/td>\n<td style=\"text-align: center\">5<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">3<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">3<\/td>\n<td style=\"text-align: center\">10<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">4<\/td>\n<td style=\"text-align: center\">4<\/td>\n<td style=\"text-align: center\">8<\/td>\n<td style=\"text-align: center\">4<\/td>\n<td style=\"text-align: center\">10<\/td>\n<\/tr>\n<tr>\n<td>Index:<\/td>\n<td style=\"text-align: center\">0<\/td>\n<td style=\"text-align: center\">1<\/td>\n<td style=\"text-align: center\">2<\/td>\n<td style=\"text-align: center\">3<\/td>\n<td style=\"text-align: center\">4<\/td>\n<td style=\"text-align: center\">5<\/td>\n<td style=\"text-align: center\">6<\/td>\n<td style=\"text-align: center\">7<\/td>\n<td style=\"text-align: center\">8<\/td>\n<td style=\"text-align: center\">9<\/td>\n<td style=\"text-align: center\">10<\/td>\n<td style=\"text-align: center\">11<\/td>\n<td style=\"text-align: center\">12<\/td>\n<td style=\"text-align: center\">13<\/td>\n<td style=\"text-align: center\">14<\/td>\n<td style=\"text-align: center\">15<\/td>\n<td style=\"text-align: center\">16<\/td>\n<td style=\"text-align: center\">17<\/td>\n<td style=\"text-align: center\">18<\/td>\n<td style=\"text-align: center\">19<\/td>\n<td style=\"text-align: center\">20<\/td>\n<td style=\"text-align: center\">21<\/td>\n<td style=\"text-align: center\">22<\/td>\n<td style=\"text-align: center\">23<\/td>\n<td style=\"text-align: center\">24<\/td>\n<td style=\"text-align: center\">25<\/td>\n<\/tr>\n<\/table>\n<\/div>\n<p>This system doesn’t quite work for the lowercase letters though, because the ASCII values of the lowercase letters are different from the capital letters. However, it simply means that we need to subtract the value of the lowercase letter ‘a’ instead of the capital ‘A’.<\/p>\n<p>So it seems I need an <i>if statement<\/i> within the loop to calculate the score depending on the case of the letters using <i>isupper<\/i> and <i>islower<\/i> functions from the <i>ctype.h<\/i> library, which I’ll include in the header too:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">int calculate_score(string word)\r\n{\r\n    \/\/ Keep track of the score\r\n    int score = 0;\r\n\r\n    \/\/ Compute the score for each character\r\n    for (int i = 0, len = strlen(word); i &lt; len; i++)\r\n    {\r\n        if (isupper(word[i]))\r\n        {\r\n            score += points[word[i] - 'A'];\r\n        }\r\n        else if (islower(word[i]))\r\n        {\r\n            score += points[word[i] - 'a'];\r\n        }\r\n    }\r\n    return score;\r\n}<\/code><\/pre><p>Since I’m using the <i>points<\/i> array in this function, I need to move it out from the main’s local scope to the global scope. The rest is easy: all I need to do is to call the function <i>calculate_score<\/i> (twice, for each word) and then compare players’ scores to determine the winner.<\/p>\n<p>And here is my final code:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">#include &lt;cs50.h&gt;\r\n#include &lt;ctype.h&gt;\r\n#include &lt;stdio.h&gt;\r\n#include &lt;string.h&gt;\r\n\r\n\/\/ points assigned to each letter of the alphabet\r\nint points[] = {1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1, 3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10};\r\n\r\nint calculate_score(string word);\r\n\r\nint main(void)\r\n{\r\n    \/\/ Prompt the user for two words\r\n    string word1 = get_string(&quot;Player 1: &quot;);\r\n    string word2 = get_string(&quot;Player 2: &quot;);\r\n\r\n    \/\/ Compute the score of each word\r\n    int score1 = calculate_score(word1);\r\n    int score2 = calculate_score(word2);\r\n\r\n    \/\/ Print the winner\r\n    if (score1 &gt; score2)\r\n    {\r\n        printf(&quot;Player 1 wins!\\n&quot;);\r\n    }\r\n    else if (score1 &lt; score2)\r\n    {\r\n        printf(&quot;Player 2 wins!\\n&quot;);\r\n    }\r\n    else\r\n    {\r\n        printf(&quot;Tie!\\n&quot;);\r\n    }\r\n}\r\n\r\nint calculate_score(string word)\r\n{\r\n    \/\/ Keep track of the score\r\n    int score = 0;\r\n\r\n    \/\/ Compute the score for each character\r\n    for (int i = 0, len = strlen(word); i &lt; len; i++)\r\n    {\r\n        if (isupper(word[i]))\r\n        {\r\n            score += points[word[i] - 'A'];\r\n        }\r\n        else if (islower(word[i]))\r\n        {\r\n            score += points[word[i] - 'a'];\r\n        }\r\n    }\r\n    return score;\r\n}<\/code><\/pre>",
            "date_published": "2024-02-25T18:38:13+05:00",
            "date_modified": "2024-02-25T18:36:58+05:00",
            "tags": [
                "CS50",
                "programming",
                "Software development"
            ],
            "author": {
                "name": "Daniel Sokolovskiy",
                "url": "https:\/\/dsokolovskiy.com\/blog\/",
                "avatar": "https:\/\/dsokolovskiy.com\/blog\/pictures\/userpic\/userpic@2x.jpg?1732048793"
            },
            "_date_published_rfc2822": "Sun, 25 Feb 2024 18:38:13 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "126033",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "126030",
            "url": "https:\/\/dsokolovskiy.com\/blog\/all\/credit-card-validation-in-c\/",
            "title": "Credit card validation in C",
            "content_html": "<p>I <a href=\"\/blog\/all\/super-mario-pyramids-in-c\/\">keep learning programming<\/a>, and today I share my baby walkthrough of the second homework from the CS50 course titled Credit.<\/p>\n<p>As a quick disclaimer, I used only tools I’ve learned from the two lessons I had so far.<\/p>\n<p>Here is the problem to solve:<\/p>\n<div class=\"question\"><p>A credit (or debit) card, of course, is a plastic card with which you can pay for goods and services. Printed on that card is a number that’s also stored in a database somewhere, so that when your card is used to buy something, the creditor knows whom to bill. There are a lot of people with credit cards in this world, so those numbers are pretty long: American Express uses 15-digit numbers, MasterCard uses 16-digit numbers, and Visa uses 13- and 16-digit numbers. And those are decimal numbers (0 through 9), not binary, which means, for instance, that American Express could print as many as 10^15 = 1,000,000,000,000,000 unique cards! (That’s, um, a quadrillion.)<\/p>\n<p>Actually, that’s a bit of an exaggeration, because credit card numbers actually have some structure to them. All American Express numbers start with 34 or 37; most MasterCard numbers start with 51, 52, 53, 54, or 55 (they also have some other potential starting numbers which we won’t concern ourselves with for this problem); and all Visa numbers start with 4. But credit card numbers also have a “checksum” built into them, a mathematical relationship between at least one number and others. That checksum enables computers (or humans who like math) to detect typos (e. g., transpositions), if not fraudulent numbers, without having to query a database, which can be slow. Of course, a dishonest mathematician could certainly craft a fake number that nonetheless respects the mathematical constraint, so a database lookup is still necessary for more rigorous checks.<\/p>\n<p>Write a program that prompts the user for a credit card number and then reports (via printf) whether it is a valid American Express, MasterCard, or Visa card number, per the definitions of each’s format herein. So that we can automate some tests of your code, we ask that your program’s last line of output be AMEX\\n or MASTERCARD\\n or VISA\\n or INVALID\\n, nothing more, nothing less. For simplicity, you may assume that the user’s input will be entirely numeric (i.e., devoid of hyphens, as might be printed on an actual card) and that it won’t have leading zeroes. But do not assume that the user’s input will fit in an int! Best to use get_long from CS50’s library to get users’ input.<\/p>\n<\/div><p>First, I’ll prompt a user to input a number using the <i>get_long<\/i> function from the CS50 library:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">#include &lt;cs50.h&gt;\r\n#include &lt;stdio.h&gt;\r\n\r\nint main(void)\r\n{\r\n    long card_number = get_long(&quot;Number: &quot;);\r\n}<\/code><\/pre><p>Next, I’ll do what seems to be the most challenging part of the problem, which is to calculate the checksum of a credit card. In the problem description, they provide additional information on Luhn’s Algorithm that determines the validity of a card as follows:<\/p>\n<ol start=\"1\">\n<li>Multiply every other digit by 2, starting with the number’s second-to-last digit, and then add those products’ digits together.<\/li>\n<li>Add the sum to the sum of the digits that weren’t multiplied by 2.<\/li>\n<li>If the total’s last digit is 0, the number is valid!<\/li>\n<\/ol>\n<p>Let’s take the card number 4003600000000014 as an example. For the sake of visibility, let me underline every other digit, starting with the number’s second-to-last digit:<\/p>\n<p><u>4<\/u> 0 <u>0<\/u> 3 <u>6<\/u> 0 <u>0<\/u> 0 <u>0<\/u> 0 <u>0<\/u> 0 <u>0<\/u> 0 <u>1<\/u> 4<\/p>\n<p>How to extract those digits from a number in C? Turns out, in maths, there is a great operation that can give us the remainder after dividing one number by another, and it’s called <i>modulo<\/i>, or mod. You can totally start laughing here, but honestly, I never heard of it before. For example, <i>1234 % 10 = 4<\/i> (with modulo operation being expressed by the percent sign), since 4 is the last digit in the number 1234.<\/p>\n<p>Okay, that was the last digit. But how to get to the second-to-last digit, and then get every other digit from there? This might be not as obvious (at least it wasn’t at first to me), but since we’re dealing with whole numbers, a simple division by 10 basically moves us to one character in a number at a time. For example, <i>1234 \/ 10 = 123,4<\/i>, but since the integer numbers get truncated, the result is actually 123.<\/p>\n<p>Pretty cool, huh? Now let’s try to get every second number using the combination of division and modulo operations in the code:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">#include &lt;cs50.h&gt;\r\n#include &lt;stdio.h&gt;\r\n\r\nlong card_number;\r\nint main(void)\r\n{\r\n    \/\/ Prompting a user to input a credit card number\r\n    card_number = get_long(&quot;Number: &quot;);\r\n\r\n    \/\/ Calculating checksum\r\n    int last_digit;\r\n    int second_to_last_digit;\r\n\r\n    while (card_number &gt; 0)\r\n    {\r\n        \/\/ Removing the last digit\r\n        last_digit = card_number % 10;\r\n        card_number \/= 10;\r\n\r\n        \/\/ Removing the second last digit\r\n        second_to_last_digit = card_number % 10;\r\n        card_number \/= 10;\r\n        printf(&quot;%i&quot;, second_to_last_digit);\r\n    }\r\n    printf(&quot;\\n&quot;);\r\n}<\/code><\/pre><p>This code prints 10000604, which are exactly the digits we need from the card number <u>4<\/u>0<u>0<\/u>3<u>6<\/u>0<u>0<\/u>0<u>0<\/u>0<u>0<\/u>0<u>0<\/u>0<u>1<\/u>4. Keep in mind it’s not a number ten million six hundred four, but individual digits printed one after another. The order of digits is reversed, though it’s irrelevant in this case.<\/p>\n<p>Next, according to Luhn’s Algorithm, I need to multiply each digit by 2 and get the sum of all of them combined. And I haven’t found a better solution than again using the same modulo and division operations, but this time on the extracted digits:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">#include &lt;cs50.h&gt;\r\n#include &lt;stdio.h&gt;\r\n\r\nlong card_number;\r\nint main(void)\r\n{\r\n    \/\/ Prompting a user to input a credit card number\r\n    card_number = get_long(&quot;Number: &quot;);\r\n\r\n    \/\/ Calculating checksum\r\n    int every_second_digit = 0;\r\n    int last_digit;\r\n    int second_to_last_digit;\r\n    int digit1;\r\n    int digit2;\r\n\r\n    while (card_number &gt; 0)\r\n    {\r\n        \/\/ Removing the last digit and adding to every_other_digit\r\n        last_digit = card_number % 10;\r\n        card_number \/= 10;\r\n\r\n        \/\/ Removing the second last digit\r\n        second_to_last_digit = card_number % 10;\r\n        card_number \/= 10;\r\n\r\n        \/\/ Mupliplying second last digit\r\n        second_to_last_digit *= 2;\r\n\r\n        \/\/ Adding digits together to get the sum of every_second_digit\r\n        digit1 = second_to_last_digit % 10;\r\n        digit2 = second_to_last_digit \/ 10;\r\n        every_second_digit += digit1 + digit2;\r\n    }\r\n    printf(&quot;%i&quot;, every_second_digit);\r\n    printf(&quot;\\n&quot;);\r\n}<\/code><\/pre><p>I’m pretty sure it could be done more elegantly, but I’m using only the knowledge I have so far from the first week of introduction to programming. Importantly, this code works, providing the result of the number 13, as you would expect from the sum of digits 2 + 1 + 2 + 8. Yay!<\/p>\n<p>Lastly, to finish off the checksum, I’m going to find every other digit, add them together, and then add both sums in the final <i>checksum<\/i> variable:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">#include &lt;cs50.h&gt;\r\n#include &lt;stdio.h&gt;\r\n\r\nlong card_number;\r\nint main(void)\r\n{\r\n    \/\/ Prompting a user to input a credit card number\r\n    card_number = get_long(&quot;Number: &quot;);\r\n\r\n    \/\/ Calculating checksum\r\n    int every_second_digit = 0;\r\n    int every_other_digit = 0;\r\n    int checksum = 0;\r\n    int last_digit;\r\n    int second_to_last_digit;\r\n    int digit1;\r\n    int digit2;\r\n\r\n    while (card_number &gt; 0)\r\n    {\r\n        \/\/ Removing the last digit and adding to every_other_digit\r\n        last_digit = card_number % 10;\r\n        card_number \/= 10;\r\n        every_other_digit += last_digit;\r\n\r\n        \/\/ Removing the second last digit\r\n        second_to_last_digit = card_number % 10;\r\n        card_number \/= 10;\r\n\r\n        \/\/ Mupliplying second last digit\r\n        second_to_last_digit *= 2;\r\n\r\n        \/\/ Adding digits together to get the sum of every_second_digit\r\n        digit1 = second_to_last_digit % 10;\r\n        digit2 = second_to_last_digit \/ 10;\r\n        every_second_digit += digit1 + digit2;\r\n    }\r\n\r\n    \/\/ Getting checksum\r\n    checksum = every_second_digit + every_other_digit;\r\n\r\n    printf(&quot;%i\\n&quot;, checksum);\r\n}<\/code><\/pre><p>This code now prints the number 20, which is exactly the kind of value I want from a valid credit card. The hardest part is done!<\/p>\n<p>Next, I’ll calculate the number of digits in the card number using a simple loop:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">\/\/ Counting the number of digits in the card number\r\n    long n = card_number;\r\n    int number_of_digits = 0;\r\n    do\r\n    {\r\n        n \/= 10;\r\n        number_of_digits++;\r\n    }\r\n    while (n != 0);<\/code><\/pre><p>To keep the value of that <i>card_number<\/i> intact, I added a new variable called <i>n<\/i> and assigned its value to <i>card_number<\/i>, so I can do the maths with the <i>n<\/i> instead. In plain English, that loop says the following: while the card number is not equal to zero, divide the card number by 10, and for every division increase the number of <i>number_of_digits<\/i> variable which I use as a counter by one.<\/p>\n<p>For example, if I were to type in the number 1234, it would go as follows:<\/p>\n<ol start=\"1\">\n<li>1234 \/ 10 = 123; the counter increases from 0 to 1;<\/li>\n<li>123,4 \/ 10 = 12; the counter increases from 1 to 2;<\/li>\n<li>12,34 \/ 10 = 1; the counter increases from 2 to 3;<\/li>\n<li>1 \/ 0 = 10; the counter increases from 3 to 4;<\/li>\n<\/ol>\n<p>Now the card number gets equal to zero, and the loop ends with the counter equal to 4, which is the correct number of digits in the number 1234.<\/p>\n<p>Next, I’ll make another counter to get the first two digits of the card number using pretty much the same logic:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">\/\/ Getting the first two digits of the card number\r\n    int first_two_digits = 0;\r\n    long i = card_number;\r\n    while (i &gt; 100)\r\n    {\r\n        i \/= 10;\r\n        first_two_digits = i;\r\n    }<\/code><\/pre><p>Lastly, I’ll check the validity of the checksum and then check what credit company the card belongs to based of the card number length and starting digits.<\/p>\n<p>So here is my final code:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">\/\/ A program in C that checks the validity of a given credit card number\r\n\r\n#include &lt;cs50.h&gt;\r\n#include &lt;stdio.h&gt;\r\n\r\nlong card_number;\r\nint main(void)\r\n{\r\n    \/\/ Prompting a user to input a credit card number\r\n    card_number = get_long(&quot;Number: &quot;);\r\n\r\n    \/\/ Counting the number of digits in the card number\r\n    long n = card_number;\r\n    int number_of_digits = 0;\r\n    do\r\n    {\r\n        n \/= 10;\r\n        number_of_digits++;\r\n    }\r\n    while (n != 0);\r\n\r\n    \/\/ Getting first two digits of the card number\r\n    int first_two_digits = 0;\r\n    long i = card_number;\r\n    while (i &gt; 100)\r\n    {\r\n        i \/= 10;\r\n        first_two_digits = i;\r\n    }\r\n\r\n    \/\/ Calculating checksum\r\n    int every_second_digit = 0;\r\n    int every_other_digit = 0;\r\n    int checksum = 0;\r\n    int last_digit;\r\n    int second_to_last_digit;\r\n    int digit1;\r\n    int digit2;\r\n\r\n    while (card_number &gt; 0)\r\n    {\r\n        \/\/ Removing last digit and adding to every_other_digit\r\n        last_digit = card_number % 10;\r\n        card_number \/= 10;\r\n        every_other_digit += last_digit;\r\n\r\n        \/\/ Removing the second last digit\r\n        second_to_last_digit = card_number % 10;\r\n        card_number \/= 10;\r\n\r\n        \/\/ Mupliplying the second last digit\r\n        second_to_last_digit *= 2;\r\n\r\n        \/\/ Adding digits together to get the sum of every_second_digit\r\n        digit1 = second_to_last_digit % 10;\r\n        digit2 = second_to_last_digit \/ 10;\r\n        every_second_digit += digit1 + digit2;\r\n    }\r\n\r\n    \/\/ Getting checksum\r\n    checksum = every_second_digit + every_other_digit;\r\n\r\n    \/\/ Checking for the card validity\r\n    int validity = checksum % 10;\r\n    if (validity == 0)\r\n    {\r\n        if ((number_of_digits == 15) &amp;&amp; (first_two_digits == 34 || first_two_digits == 37))\r\n        {\r\n            printf(&quot;AMEX\\n&quot;);\r\n        }\r\n        else if ((number_of_digits == 16) &amp;&amp; (first_two_digits &gt;= 51 &amp;&amp; first_two_digits &lt;= 55))\r\n        {\r\n            printf(&quot;MASTERCARD\\n&quot;);\r\n        }\r\n        else if ((number_of_digits == 16 || number_of_digits == 13) &amp;&amp; (first_two_digits \/ 10 == 4))\r\n        {\r\n            printf(&quot;VISA\\n&quot;);\r\n        }\r\n        else\r\n        {\r\n            printf(&quot;INVALID\\n&quot;);\r\n        }\r\n    }\r\n    else\r\n    {\r\n        printf(&quot;INVALID\\n&quot;);\r\n    }\r\n}<\/code><\/pre><h2>Update<\/h2>\n<p>A week later after posting this solution, I decided to get back to this problem and see if I could improve the code, particularly focusing on the checksum part as it’s essentially the main part.<\/p>\n<p>Here is my updated code for this function:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">\/\/ Calculate checksum using Luhn's Algorithm\r\nint calculate_checksum(long long number)\r\n{\r\n    int sum = 0;\r\n    int digit;\r\n    bool is_second_digit = false;\r\n\r\n    while (number &gt; 0)\r\n    {\r\n        digit = number % 10; \/\/ Get the last digit\r\n        number \/= 10; \/\/ Reduce the number by one digit\r\n\r\n        if (is_second_digit)\r\n        {\r\n            digit *= 2;\r\n            sum += digit % 10 + digit \/ 10; \/\/ Split double numbers into single digits, e.g. 12 into 1 and 2\r\n        }\r\n        else\r\n        {\r\n            sum += digit;\r\n        }\r\n\r\n        \/\/ Switch the boolean, alternating between odd and even digits\r\n        is_second_digit = !is_second_digit;\r\n    }\r\n\r\n    return sum;\r\n}<\/code><\/pre>",
            "date_published": "2024-02-25T14:25:23+05:00",
            "date_modified": "2024-03-11T20:07:37+05:00",
            "tags": [
                "C",
                "CS50",
                "programming"
            ],
            "author": {
                "name": "Daniel Sokolovskiy",
                "url": "https:\/\/dsokolovskiy.com\/blog\/",
                "avatar": "https:\/\/dsokolovskiy.com\/blog\/pictures\/userpic\/userpic@2x.jpg?1732048793"
            },
            "_date_published_rfc2822": "Sun, 25 Feb 2024 14:25:23 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "126030",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "122016",
            "url": "https:\/\/robertblinov.net\/blog\/all\/nocss\/",
            "title": "No-CSS Club",
            "content_html": "<p>Structural simplicity is not necessarily visual simplicity. Modular devices are structurally simple, but often physically bulky. MacBook power bricks are visually simple, but structurally too complex to be repaired.<\/p>\n<p>Philosophically, structural simplicity is the one to prioritise. Form follows function.<\/p>\n<p>⁂<\/p>\n<p>Designing a webstead around the avoidance of CSS leads to a reduction in bloat and an improvement in structure.<\/p>\n<p>It also <i>makes plain sense<\/i>. Visitors are already setting their preferences, whether font size, color theme, or window width. I’m just extending this way of thinking to style sheets, which can be customised thru browsers.<\/p>\n<p>I’m happy to have my webstead listed in the <a href=\"https:\/\/nocss.club\">No-CSS Club<\/a>. Some day, this blog too will wave goodbye to cascades.<\/p>\n",
            "date_published": "2023-08-02T13:57:23+05:00",
            "date_modified": "2025-02-10T20:15:50+05:00",
            "tags": [
                "design",
                "DOPE",
                "hues",
                "my webstead",
                "programming",
                "the web",
                "websteads"
            ],
            "author": {
                "name": "Robert",
                "url": "https:\/\/robertblinov.net\/blog\/",
                "avatar": "https:\/\/robertblinov.net\/blog\/pictures\/userpic\/userpic@2x.jpg?1739870896"
            },
            "_date_published_rfc2822": "Wed, 02 Aug 2023 13:57:23 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "122016",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "121951",
            "url": "https:\/\/robertblinov.net\/blog\/all\/merceneros\/",
            "title": "Merceneros visual identity",
            "content_html": "<p><a href=\"https:\/\/merceneros.com\">Merceneros<\/a> is a coöperative offering technical services to the Monero economy.<\/p>\n<p>I designed its visual identity based on the trope of programming, having the colors allude to Monero:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/robertblinov.net\/blog\/pictures\/merceneros-com.png\" width=\"2560\" height=\"1628.0412371134\" alt=\"\" \/>\n<\/div>\n<p>This design is super-universal — the list of values in brackets varies with context, and will expand with the group offering more services:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/robertblinov.net\/blog\/pictures\/merceneros-brackets.png\" width=\"1500\" height=\"1000\" alt=\"\" \/>\n<\/div>\n<p>Also, this visual identity needs no special graphics for implementation — only the JetBrains Mono typeface.<\/p>\n<p>There’s a compact version of the logo too:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/robertblinov.net\/blog\/pictures\/merceneros-logo.png\" width=\"500\" height=\"500\" alt=\"\" \/>\n<\/div>\n<p>Here it is in the chats. The second logo is an internal one, with a caret instead of a bracket:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/robertblinov.net\/blog\/pictures\/merceneros-logos-chat.png\" width=\"113\" height=\"558\" alt=\"\" \/>\n<\/div>\n<p>I went from start to finish in less than a day.<\/p>\n",
            "date_published": "2023-07-28T23:57:10+05:00",
            "date_modified": "2025-08-27T17:28:30+05:00",
            "tags": [
                "design",
                "hues",
                "logos",
                "monero",
                "my logos",
                "programming",
                "typography",
                "undertakings"
            ],
            "author": {
                "name": "Robert",
                "url": "https:\/\/robertblinov.net\/blog\/",
                "avatar": "https:\/\/robertblinov.net\/blog\/pictures\/userpic\/userpic@2x.jpg?1739870896"
            },
            "_date_published_rfc2822": "Fri, 28 Jul 2023 23:57:10 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "121951",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "121886",
            "url": "https:\/\/robertblinov.net\/blog\/all\/no-js\/",
            "title": "No-JS Club",
            "content_html": "<p>My webstead has never had JS outside of some blog features.<\/p>\n<p>I’m happy that it has now been listed in the <a href=\"https:\/\/no-js.club\">No-JS Club<\/a>!<\/p>\n",
            "date_published": "2023-07-25T21:41:47+05:00",
            "date_modified": "2025-02-10T20:15:43+05:00",
            "tags": [
                "DOPE",
                "my webstead",
                "programming",
                "the web"
            ],
            "author": {
                "name": "Robert",
                "url": "https:\/\/robertblinov.net\/blog\/",
                "avatar": "https:\/\/robertblinov.net\/blog\/pictures\/userpic\/userpic@2x.jpg?1739870896"
            },
            "_date_published_rfc2822": "Tue, 25 Jul 2023 21:41:47 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "121886",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "126162",
            "url": "https:\/\/robertblinov.net\/blog\/all\/sunset-b1\/",
            "title": "Sunset theme for Nova",
            "content_html": "<p>To write CSS and JS code, I use the code editor <a href=\"https:\/\/nova.app\">Nova<\/a>. Its dark mode is acceptable but definitely not great:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/robertblinov.net\/blog\/pictures\/Nova-dark.png\" width=\"2560\" height=\"1631.2643678161\" alt=\"\" \/>\n<\/div>\n<p>Therefore I made my own theme, Sunset:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/robertblinov.net\/blog\/pictures\/Sunset.png\" width=\"2560\" height=\"1631.2643678161\" alt=\"\" \/>\n<\/div>\n<p>It is based on reddish hues, which are good at lowering eye-strain. Text is colored differently than in dark mode, comments are indicated with italics.<\/p>\n<p class=\"loud\"><a href=\"https:\/\/extensions.panic.com\/extensions\/Robert\/Robert.Sunset\/\">↓ Download beta 1<\/a><\/p>\n",
            "date_published": "2021-01-18T18:03:41+05:00",
            "date_modified": "2024-11-13T11:58:18+05:00",
            "tags": [
                "design",
                "health",
                "hues",
                "programming",
                "software",
                "Sunset",
                "undertakings"
            ],
            "author": {
                "name": "Robert",
                "url": "https:\/\/robertblinov.net\/blog\/",
                "avatar": "https:\/\/robertblinov.net\/blog\/pictures\/userpic\/userpic@2x.jpg?1739870896"
            },
            "_date_published_rfc2822": "Mon, 18 Jan 2021 18:03:41 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "126162",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "127874",
            "url": "https:\/\/robertblinov.net\/blog\/all\/bugs\/",
            "title": "Bugs in own programs",
            "content_html": "<p>I feel great joy when finding and squashing bugs in my own programs.<\/p>\n",
            "date_published": "2021-01-02T00:23:12+05:00",
            "date_modified": "2024-12-04T02:11:25+05:00",
            "tags": [
                "feelings",
                "growth",
                "Life",
                "me",
                "programming"
            ],
            "author": {
                "name": "Robert",
                "url": "https:\/\/robertblinov.net\/blog\/",
                "avatar": "https:\/\/robertblinov.net\/blog\/pictures\/userpic\/userpic@2x.jpg?1739870896"
            },
            "_date_published_rfc2822": "Sat, 02 Jan 2021 00:23:12 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "127874",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "122600",
            "url": "https:\/\/robertblinov.net\/blog\/all\/tg-2020-w21\/",
            "title": "My Telegram posts on 2020’s week 21",
            "content_html": "<p><a href=\"https:\/\/robertblinov.net\/blog\/all\/telegram-2020-apr-16-may-16\/\">Weeks 16...20<\/a> ←→ <a href=\"https:\/\/robertblinov.net\/blog\/all\/telegram-2020-w22\/\">Week 22<\/a><\/p>\n<h2>Tuesday, May 19<\/h2>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/robertblinov.net\/blog\/pictures\/Zoompocalypse.png\" width=\"262\" height=\"264\" alt=\"\" \/>\n<\/div>\n<p>Made myself a standing workplace outside:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/robertblinov.net\/blog\/pictures\/Standing-workplace.jpg\" width=\"1280\" height=\"870\" alt=\"\" \/>\n<\/div>\n<h2>Wednesday, May 20<\/h2>\n<p>From <a href=\"https:\/\/nytimes.com\/2020\/05\/20\/opinion\/volodymyr-zelensky-ukraine-coronavirus.html\">President Zelensky’s NYT op-ed<\/a>: “Ukraine remains a good partner and friend of the United States. We received the military assistance we needed to continue to ensure our country’s independence.”<\/p>\n<p>Independence, you say? <i>Needing<\/i> something = being dependent on that something’s provider.<\/p>\n<h2>Thursday, May 21<\/h2>\n<p>I love drinking tea with ice cream.<\/p>\n<h2>Friday, May 22<\/h2>\n<p>I always click <i>Submit<\/i> instead of the arrows. Stupid design:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/robertblinov.net\/blog\/pictures\/GoogleMeet.png\" width=\"870\" height=\"1280\" alt=\"\" \/>\n<\/div>\n<p>I’m writing a program that will help me write another program.<\/p>\n<p>People should not be working towards 1TB\/s internet, but towards files that take up less space.<\/p>\n<h2>Saturday, May 23<\/h2>\n<p>Evil doesn’t exist. Interests do.<\/p>\n<p>It’s a good thing that English got rid of the long s. If we ſtill had it today, reading would be much ſlower and ſlippier.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/robertblinov.net\/blog\/pictures\/LongS.png\" width=\"1278\" height=\"194\" alt=\"\" \/>\n<\/div>\n<h2>Sunday, May 24<\/h2>\n<p>Government bureaucracy is not always bad: it’s a strong filter that stops all extreme initiatives.<\/p>\n",
            "date_published": "2020-05-25T15:47:16+05:00",
            "date_modified": "2024-10-21T12:32:14+05:00",
            "tags": [
                "drinks",
                "food",
                "Life",
                "might",
                "my Telegram channel",
                "programming",
                "tongue",
                "Ukraine"
            ],
            "author": {
                "name": "Robert",
                "url": "https:\/\/robertblinov.net\/blog\/",
                "avatar": "https:\/\/robertblinov.net\/blog\/pictures\/userpic\/userpic@2x.jpg?1739870896"
            },
            "_date_published_rfc2822": "Mon, 25 May 2020 15:47:16 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "122600",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        },
        {
            "id": "124633",
            "url": "https:\/\/ilyabirman.net\/meanwhile\/all\/ass\/",
            "title": "Ångström Style System for Cocoa",
            "content_html": "<p>While developing <a href=\"http:\/\/ilyabirman.net\/projects\/angstrom\/\">Ångström<\/a>, the unit converter for the iPhone (check it out!), Alex Babaev and I have come up with the Ångström Style System.<\/p>\n<p>ÅSS (hey, why not) is a JSON-driven styling engine for Cocoa with Dropbox synchronization and shake-to-refresh. It is a great way to separate the code of the app from its look and feel. It helped me try out different aspects of the color scheme, the fonts, the spacings and, most importantly the animations, without making Alex rebuild the app every time I wanted to change something.<\/p>\n<h2>Playing with the text caret<\/h2>\n<p>One of the many things we were obsessing over in Ångström was the text caret animation:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/ilyabirman.net\/meanwhile\/pictures\/angstrom-cursor.gif\" width=\"328\" height=\"160\" alt=\"\" \/>\n<\/div>\n<p>This is an animated gif, make sure to <a href=\"https:\/\/itunes.apple.com\/app\/id783839219?mt=8\">download the app<\/a> and look at the real thing.<\/p>\n<p>I wanted the caret to stick out much below and above the text. I wanted it to move like an elastic and bouncy string (whatever that is). I wanted to make it stretch and squeeze, not just blink. There was no way I could explain this in technical terms to Alex. How far the line should stretch? How fast the animations should be? Who knows. I needed a way to play with all the parameters until it felt right.<\/p>\n<p>So I wrote Alex a letter explaining my idea in vague terms. I asked for a way to control the length and the opacity of both the long and the short states of the caret and the transition times between them. After having played with this parameters for some time I figured out I could not make the caret behave exactly as I wanted. Six variables were not enough. We have gradually added the variables for animation easing, the delays and the caret width.<\/p>\n<p>This is the final “stylesheet” for the caret, after hours of tweaking:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">&quot;cursor&quot;: {\r\n  &quot;showTime&quot;: 0.2,\r\n  &quot;hideTime&quot;: 0.2,\r\n\r\n  &quot;color&quot;: &quot;@colors.textNumberColor&quot;,\r\n\r\n  &quot;period12&quot;: 0.4,\r\n  &quot;timingType12&quot;: &quot;linear&quot;,\r\n\r\n  &quot;period21&quot;: 0.2,\r\n  &quot;timingType21&quot;: &quot;easeOut&quot;,\r\n\r\n  &quot;height1&quot;: 48.0,\r\n  &quot;width1&quot;: 2.0,\r\n  &quot;delay1&quot;: 0.3,\r\n  &quot;alpha1&quot;: 1.0,\r\n\r\n  &quot;height2&quot;: 78.0,\r\n  &quot;width2&quot;: 1.0,\r\n  &quot;delay2&quot;: 0.1,\r\n  &quot;alpha2&quot;: 0.33\r\n},<\/code><\/pre><p>This fragment is actually about 3% of the whole Ångström’s stylesheet.<\/p>\n<h2>Dropbox sync and shake-to-refresh<\/h2>\n<p>The two things that make ÅSS particularly awesome are Dropbox sync and shake-to-refresh.<\/p>\n<p>Moving the style variables from the code to an external file is a useful idea all by itself: I could have been playing with the parameters and rebuilding the app having no clue about Objective-C. As far as I understand, this is how Brent Simmons’s <a href=\"http:\/\/inessential.com\/2013\/06\/27\/open_source_db5\">DB5<\/a> works.<\/p>\n<p>But we wanted to make ÅSS a real pleasure to use (no pun intended), eliminating the need not only to rebuild, but even to restart the app. Here is how the process of refining something looked for me thanks to ÅSS:<\/p>\n<ol start=\"1\">\n<li>Open the app on my iPhone and go to the screen I want to adjust.<\/li>\n<li>Open the app’s ÅSS stylesheet from the Dropbox folder with Sublime Text on my Mac.<\/li>\n<li>Change the parameters in the file and save it.<\/li>\n<li>Shake my iPhone to see the change immediately.<\/li>\n<\/ol>\n<p>So this is literally <i>live tuning of a running app<\/i>.<\/p>\n<p>There is a different approach to styling: put sliders with the parameters to the Settings app during development. While this may look nice, we think it is very counter-productive. You don’t want to be constantly switching between the app you are designing and the Settings app. You don’t want to be scrolling through tens or hundreds of variables on the iPhone screen. You don’t want to struggle entering a color’s #rrggbb value on the iPhone keyboard. Sublime Text on a computer synced with the iPhone via Dropbox works so much better.<\/p>\n<p>Alex has written <a href=\"http:\/\/www.lonelybytes.com\/blog-en\/2014\/3\/23\/styling-an-ios-application-dplstyler\">a post on the internals of the system<\/a>, check it out. It explains the architecture and features some code examples.<\/p>\n",
            "date_published": "2014-04-10T03:37:05+05:00",
            "date_modified": "2023-11-28T23:33:56+05:00",
            "tags": [
                "Ångström",
                "design",
                "programming"
            ],
            "author": {
                "name": "Ilya Birman",
                "url": "https:\/\/ilyabirman.net\/meanwhile\/",
                "avatar": "https:\/\/ilyabirman.net\/meanwhile\/pictures\/userpic\/userpic@2x.jpg?1573933764"
            },
            "_date_published_rfc2822": "Thu, 10 Apr 2014 03:37:05 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "124633",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": null,
                "og_images": []
            }
        }
    ],
    "_e2_version": 4079,
    "_e2_ua_string": "Aegea 11.0 (v4079e)"
}