<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Posts on Konstantin's Blog</title><link>https://konstantin.gladyou.click/posts/</link><description>Recent content in Posts on Konstantin's Blog</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Wed, 30 Jul 2025 23:32:00 +0000</lastBuildDate><atom:link href="https://konstantin.gladyou.click/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>AI Simulates the Martingale Betting System with Cursor Agents</title><link>https://konstantin.gladyou.click/posts/2025-07-30-ai-simulates-the-martingale-betting-system-with-cursor-agents/</link><pubDate>Wed, 30 Jul 2025 23:32:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2025-07-30-ai-simulates-the-martingale-betting-system-with-cursor-agents/</guid><description>A quick, hands-on simulation of the Martingale betting system, built and tested using Cursor’s AI agents. You’ll watch me prompt an AI to write a Monte Carlo script in TypeScript, run the simulation to test the strategy, and use a different AI model to perform a complete code review of the generated logic. Think of it as a live demonstration of AI-driven development—not financial advice, but a clear overview of how AI can rapidly build and validate a complex simulation.</description><content:encoded><![CDATA[<p>A quick, hands-on simulation of the Martingale betting system, built and tested using Cursor’s AI agents. You’ll watch me prompt an AI to write a Monte Carlo script in TypeScript, run the simulation to test the strategy, and use a different AI model to perform a complete code review of the generated logic. Think of it as a live demonstration of AI-driven development—not financial advice, but a clear overview of how AI can rapidly build and validate a complex simulation.</p>

<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
  <iframe src="https://www.youtube.com/embed/azkaMHElUVU" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>

<p>The GitHub: <a href="https://github.com/bukov-ka/martingale" target="_blank"><a href="https://github.com/bukov-ka/martingale">https://github.com/bukov-ka/martingale</a></a></p>
]]></content:encoded></item><item><title>Quick peek at the Cursor AI agents</title><link>https://konstantin.gladyou.click/posts/2025-07-06-quick-peek-at-the-cursor-ai-agents/</link><pubDate>Sun, 06 Jul 2025 16:12:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2025-07-06-quick-peek-at-the-cursor-ai-agents/</guid><description>A quick, hands-on walk-through of building a Fridge Puzzle game in the browser using Cursor’s AI agents. You’ll watch me bounce between GPT-4-o, O3 and Claude Sonnet, generate the UI, wire up the rotate-row/column logic, handle window resizing, and deploy a playable demo. Think of it as a live tutorial and tool-tour—not production code, but a clear overview of how AI can speed up game prototyping.
The final game: https://bukov-ka.github.io/fridge-puzzle/ The GitHub: https://github.</description><content:encoded><![CDATA[<p>A quick, hands-on walk-through of building a Fridge Puzzle game in the browser using Cursor’s AI agents. You’ll watch me bounce between GPT-4-o, O3 and Claude Sonnet, generate the UI, wire up the rotate-row/column logic, handle window resizing, and deploy a playable demo. Think of it as a live tutorial and tool-tour—not production code, but a clear overview of how AI can speed up game prototyping.</p>

<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
  <iframe src="https://www.youtube.com/embed/r2w30Ad-X-A" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>

<p>The final game: <a href="https://bukov-ka.github.io/fridge-puzzle/" target="_blank"><a href="https://bukov-ka.github.io/fridge-puzzle/">https://bukov-ka.github.io/fridge-puzzle/</a></a>
The GitHub: <a href="https://github.com/bukov-ka/fridge-puzzle" target="_blank"><a href="https://github.com/bukov-ka/fridge-puzzle">https://github.com/bukov-ka/fridge-puzzle</a></a></p>
]]></content:encoded></item><item><title>CloudFormation Profiler</title><link>https://konstantin.gladyou.click/posts/2024-12-29-cloudformation-profiler/</link><pubDate>Sun, 29 Dec 2024 10:12:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2024-12-29-cloudformation-profiler/</guid><description>&lt;img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_12784.webp" alt="DALL·E 2024-12-29 10.08.32 - A landscape-oriented logo design featuring multiple simple cloud icons in the background and a large magnifying glass in the foreground, symbolizing a.webp" title="DALL·E 2024-12-29 10.08.32 - A landscape-oriented logo design featuring multiple simple cloud icons in the background and a large magnifying glass in the foreground, symbolizing a.webp">
&lt;p>I couldn’t find a good &lt;a href="https://The tool is available on GitHub: https://github.com/bukov-ka/cloudformation-profiler" target="_blank">CloudFormation profiler&lt;/a>, so I built my own. CloudFormation Profiler analyzes stack events and shows resource deployment durations. It’s especially useful when you’re trying to optimize a stack you’re unfamiliar with or identify slow deployments.&lt;/p></description><content:encoded><![CDATA[<img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_12784.webp" alt="DALL·E 2024-12-29 10.08.32 - A landscape-oriented logo design featuring multiple simple cloud icons in the background and a large magnifying glass in the foreground, symbolizing a.webp" title="DALL·E 2024-12-29 10.08.32 - A landscape-oriented logo design featuring multiple simple cloud icons in the background and a large magnifying glass in the foreground, symbolizing a.webp">
<p>I couldn’t find a good <a href="https://The tool is available on GitHub: https://github.com/bukov-ka/cloudformation-profiler" target="_blank">CloudFormation profiler</a>, so I built my own. CloudFormation Profiler analyzes stack events and shows resource deployment durations. It’s especially useful when you’re trying to optimize a stack you’re unfamiliar with or identify slow deployments.</p>
<p>Example Output</p>
<pre>
Analyzing stack: GravitygameStack

Resource deployment times (sorted by duration):

Resource: GravitygameStack (AWS::CloudFormation::Stack)
Start Time: 2023-10-19T11:33:23.937Z
End Time: 2023-10-19T11:35:07.854Z
Duration: 103.92 seconds

Resource: DeployWebsiteCustomResourceD116527B (Custom::CDKBucketDeployment)
Start Time: 2023-10-19T11:33:30.495Z
End Time: 2023-10-19T11:35:01.322Z
Duration: 90.83 seconds

Resource: DeployGameOfGravityWebsiteCustomResource26889C77 (Custom::CDKBucketDeployment)
Start Time: 2023-10-19T11:33:30.478Z
End Time: 2023-10-19T11:34:44.540Z
Duration: 74.06 seconds
</pre>
<p>Try It Out
The tool is available on GitHub: <a href="https://github.com/bukov-ka/cloudformation-profiler">https://github.com/bukov-ka/cloudformation-profiler</a>.</p>]]></content:encoded></item><item><title>AI Coding Session Video</title><link>https://konstantin.gladyou.click/posts/2024-08-27-ai-coding-session-video/</link><pubDate>Tue, 27 Aug 2024 06:46:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2024-08-27-ai-coding-session-video/</guid><description>People keep asking me to show how I code with AI. That&amp;rsquo;s why I made this video where I create a web application from scratch in 1 hour:
Watching me code all the time might be boring, so I recommend using the navigation links to check the parts you&amp;rsquo;re interested in.</description><content:encoded><![CDATA[<p>People keep asking me to show how I code with AI. That&rsquo;s why I made this video where I create a web application from scratch in 1 hour:</p>

<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
  <iframe src="https://www.youtube.com/embed/aL7RhpeDXjI" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>

<p>Watching me code all the time might be boring, so I recommend using the navigation links to check the parts you&rsquo;re interested in.</p>
]]></content:encoded></item><item><title>New ChatGPT - New Game</title><link>https://konstantin.gladyou.click/posts/2024-06-08-new-chatgpt-new-game/</link><pubDate>Sat, 08 Jun 2024 09:22:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2024-06-08-new-chatgpt-new-game/</guid><description>&lt;img src="https://bukov-ka.github.io/ArrowStand/assets/intro.png" alt="" />
About a year ago, I wrote a &lt;a href="https://konstantin.gladyou.click/posts/2023-10-24-chatgpt-has-written-a-game-for-me-game-of-gravity-caveman-tumble/" target="_blank">game&lt;/a>. At that time, it was version 3.5 and early version 4. A year has passed, and I asked ChatGPT to create another game for me. Behold...
&lt;center>&lt;h1>&lt;a href="https://bukov-ka.github.io/ArrowStand/" target="_blank">Arrow Stand&lt;/a>&lt;/h1>&lt;/center></description><content:encoded><![CDATA[<img src="https://bukov-ka.github.io/ArrowStand/assets/intro.png" alt="" />
About a year ago, I wrote a <a href="https://konstantin.gladyou.click/posts/2023-10-24-chatgpt-has-written-a-game-for-me-game-of-gravity-caveman-tumble/" target="_blank">game</a>. At that time, it was version 3.5 and early version 4. A year has passed, and I asked ChatGPT to create another game for me. Behold...
<center><h1><a href="https://bukov-ka.github.io/ArrowStand/" target="_blank">Arrow Stand</a></h1></center>
<p>Let me start with a brief list of the changes I&rsquo;ve noticed:</p>
<ol>
<li>Big context makes a huge difference.</li> Now the whole codebase (40 kilobytes) and game design document (5k) can be included in each request. Not only that, but all the lengthy replies fit in the context, and I never saw the 'Message too long' error. Previously, I had to be really careful about what to include.
<li>The model is really good and gives full code, not just changes.</li> Combined with the previous point, it's a game changer. Now I send the whole codebase and documentation and get back file contents that can be copy/pasted. Previously, I had to carefully go through all the files making the suggested changes. It was a boring and error-prone process, which is gone now. The quality of the answers is extremely good, with almost no bugs introduced and no time wasted on debugging and fixing.
<li>Multimodal capabilities are useful.</li> HTML/CSS design is still tricky with ChatGPT, but it's much easier now. You can send a screenshot, and the model will understand you perfectly:
<br>
<p><img style="border:solid black 1px" width="50&#37;" src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_12040.png" alt="" title=""></p>
<br>
You can generate graphics as well, though I found Midjourney gave much better results. Generating music and sounds was not a problem either (with <a href="https://suno.com/">suno.com</a>), but I haven't figured out licensing and haven't included it in the game.
<li>Experience with AIs helps.</li> I use LLMs every day. I found it much easier to get good results than before. People talk about prompt engineering, but I think it's more important to build up product management skills. I understand ChatGPT's limitations and can split and simplify the functionality to better fit the tool. Just like in real life: you have to shape your requirements according to the resources you have.
</ol>
<p>Let&rsquo;s dive deeper now. Here is the chat with which I started the development: <a href="https://chatgpt.com/share/6722ddd1-6cb6-4f43-8ca4-b566124dceb4" target="_blank">link</a>
The prompt I started with was:</p>
<pre>
I want to create a small browser game called "Arrow Stand". The gameplay is simple: there is some terrain with walls, motes and grass. A player can place some amount of arrow shooters on any place of the map. They stay fixed on the places. Then an attack begins. The attackers can't shoot and just attack the closest arrow shooter. 
First I need you to expand the gameplay. Please do not add additional mechanics and just fill the gaps.
As a first step please ask me any questions about the gameplay to ensure everything is covered.
</pre>
<p>You can see how fast ChatGPT came up with a working prototype and gameplay and technical specs. BTW the specs are really important. Here is the final document after many updates: <a href="https://docs.google.com/document/d/1U-n0RU9r7k4elrNqC3DsBZBTMG5d0qQ9iyolGPzxT4I/edit#heading=h.w5kog8fj4kfv" target="_blank">link</a>. When close to the project completion I stopped updating the document and stopped to include it into prompts and that was a mistake! ChatGPT manages to understand the game logic based on the code, but quality of the responses is much higher when there is a separate text description of the end result.</p>
<p>Then I asked ChatGPT to create a script that copies all the source code into one file:
<lj-spoiler title="Click to show"></p>
<!-- HTML generated using hilite.me --><div style="background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;"><pre style="margin: 0; line-height: 125&#37;"><span style="color: #008800; font-weight: bold">import</span> <span style="color: #0e84b5; font-weight: bold">os</span>
<p><span style="color: #008800; font-weight: bold">def</span> <span style="color: #0066BB; font-weight: bold">get_files_with_extension</span>(directory, extensions, skip_dirs, skip_files):
file_list <span style="color: #333333">=</span> []
<span style="color: #008800; font-weight: bold">for</span> root, dirs, files <span style="color: #000000; font-weight: bold">in</span> os<span style="color: #333333">.</span>walk(directory):
<span style="color: #888888"># Skip directories that are in the skip_dirs list</span>
dirs[:] <span style="color: #333333">=</span> [d <span style="color: #008800; font-weight: bold">for</span> d <span style="color: #000000; font-weight: bold">in</span> dirs <span style="color: #008800; font-weight: bold">if</span> d <span style="color: #000000; font-weight: bold">not</span> <span style="color: #000000; font-weight: bold">in</span> skip_dirs]</p>
<pre><code>    &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;for&lt;/span&gt; &lt;span style=&quot;color: #007020&quot;&gt;file&lt;/span&gt; &lt;span style=&quot;color: #000000; font-weight: bold&quot;&gt;in&lt;/span&gt; files:
        &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #007020&quot;&gt;file&lt;/span&gt; &lt;span style=&quot;color: #000000; font-weight: bold&quot;&gt;in&lt;/span&gt; skip_files:
            &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;continue&lt;/span&gt;
        &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #007020&quot;&gt;any&lt;/span&gt;(&lt;span style=&quot;color: #007020&quot;&gt;file&lt;/span&gt;&lt;span style=&quot;color: #333333&quot;&gt;.&lt;/span&gt;lower()&lt;span style=&quot;color: #333333&quot;&gt;.&lt;/span&gt;endswith(ext) &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;for&lt;/span&gt; ext &lt;span style=&quot;color: #000000; font-weight: bold&quot;&gt;in&lt;/span&gt; extensions):
            file_list&lt;span style=&quot;color: #333333&quot;&gt;.&lt;/span&gt;append(os&lt;span style=&quot;color: #333333&quot;&gt;.&lt;/span&gt;path&lt;span style=&quot;color: #333333&quot;&gt;.&lt;/span&gt;join(root, &lt;span style=&quot;color: #007020&quot;&gt;file&lt;/span&gt;))
&lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;return&lt;/span&gt; file_list
</code></pre>
<p><span style="color: #008800; font-weight: bold">def</span> <span style="color: #0066BB; font-weight: bold">extract_content_and_write_to_log</span>(file_list):
<span style="color: #008800; font-weight: bold">with</span> <span style="color: #007020">open</span>(<span style="background-color: #fff0f0">'output.log'</span>, <span style="background-color: #fff0f0">'w'</span>, encoding<span style="color: #333333">=</span><span style="background-color: #fff0f0">'utf-8'</span>) <span style="color: #008800; font-weight: bold">as</span> output_file:
<span style="color: #008800; font-weight: bold">for</span> file_path <span style="color: #000000; font-weight: bold">in</span> file_list:
<span style="color: #008800; font-weight: bold">with</span> <span style="color: #007020">open</span>(file_path, <span style="background-color: #fff0f0">'r'</span>, encoding<span style="color: #333333">=</span><span style="background-color: #fff0f0">'utf-8'</span>) <span style="color: #008800; font-weight: bold">as</span> input_file:
content <span style="color: #333333">=</span> input_file<span style="color: #333333">.</span>read()
output_file<span style="color: #333333">.</span>write(f<span style="background-color: #fff0f0">&quot;&lt;{file_path}&gt;</span><span style="color: #666666; font-weight: bold; background-color: #fff0f0">\n</span><span style="background-color: #fff0f0"><code>&lt;/span&gt;&lt;span style=&quot;color: #666666; font-weight: bold; background-color: #fff0f0&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0&quot;&gt;{content}&lt;/span&gt;&lt;span style=&quot;color: #666666; font-weight: bold; background-color: #fff0f0&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0&quot;&gt;</code></span><span style="color: #666666; font-weight: bold; background-color: #fff0f0">\n</span><span style="background-color: #fff0f0">&quot;</span>)</p>
<p><span style="color: #008800; font-weight: bold">if</span> <strong>name</strong> <span style="color: #333333">==</span> <span style="background-color: #fff0f0">&quot;<strong>main</strong>&quot;</span>:
target_directory <span style="color: #333333">=</span> <span style="background-color: #fff0f0">&quot;../../&quot;</span>  <span style="color: #888888"># Replace this with the path to your target directory</span>
extensions <span style="color: #333333">=</span> [<span style="background-color: #fff0f0">'.ts'</span>, <span style="background-color: #fff0f0">'.tsx'</span>, <span style="background-color: #fff0f0">'.js'</span>, <span style="background-color: #fff0f0">'.json'</span>, <span style="background-color: #fff0f0">'.html'</span>, <span style="background-color: #fff0f0">'.css'</span>]
skip_dirs <span style="color: #333333">=</span> [<span style="background-color: #fff0f0">'node_modules'</span>, <span style="background-color: #fff0f0">'.git'</span>, <span style="background-color: #fff0f0">'dist'</span>]  <span style="color: #888888"># Add any directories you want to skip here</span>
skip_files <span style="color: #333333">=</span> [<span style="background-color: #fff0f0">'package-lock.json'</span>]  <span style="color: #888888"># Add any files you want to skip here</span></p>
<pre><code>files_to_process &lt;span style=&quot;color: #333333&quot;&gt;=&lt;/span&gt; get_files_with_extension(target_directory, extensions, skip_dirs, skip_files)
extract_content_and_write_to_log(files_to_process)
</code></pre>
<p></pre></div>
</lj-spoiler>
As a result, there is a file in the format:</p>
<pre>
&lt;filename1&gt;
```
&lt;file content1&gt;
```

&lt;filename2&gt;
```
&lt;file content2&gt;
```
</pre>
<p>I included such files as package.json and tsconfig.json, because ChatGPT helped me configure those as well. And each of my prompts included all the source code and gameplay specs (many thanks to the big context). It makes the chats hard to read because it is a lot of text, but the results were impressive. All my &ldquo;prompt engineering&rdquo; was to shoot everything I had and ask, &ldquo;What should I implement next?&rdquo;. Here is an example: <a href="https://chatgpt.com/share/dec7c39c-ac9c-4e76-80be-0350f03be06b" target="_blank">link</a>.</p>
<p>At an early stage, I asked ChatGPT to split the game logic into several files: <a href="https://chatgpt.com/share/f298fb91-249c-4be8-ba53-353d6fa529b1" target="_blank">link</a>. With this, it was much easier to copy/paste results from ChatGPT to the source code. ChatGPT generated a full file content with the name in the first line, and I just replaced the whole file.</p>
<p>From time to time, I asked ChatGPT to refactor the code. A year ago, each refactoring was a problem. With ChatGPT-4, it&rsquo;s just one request. Here, I asked it to extract config into a separate file and then to implement area damage for wizards: <a href="https://chatgpt.com/share/d572ed59-7523-4006-86e6-37b78082f043" target="_blank">link</a>. Two significant changes with just two requests. Really easy!</p>
<p>And that is my general impression of the new ChatGPT. I just make a request and get a result. Here, I asked to make the spiders avoid stepping on each other. It is a significant behavior change, but it was done easily: <a href="https://chatgpt.com/share/3f42d17b-f52b-4d12-a9d6-6f727caf1956" target="_blank">link</a>. Another example is the winning logic. Initially, the spiders always won; all the defenders were dead at some point, the only difference was the number of spiders killed. My son didn&rsquo;t like this, so I changed the logic to reach 2000 points to win: <a href="https://chatgpt.com/share/1e311a52-97b3-45a4-8b46-31e06fd51902" target="_blank">link</a>.</p>
<p>I spent about 30 hours building this game, which is about 10% of the effort I would have had to put in if I did the same project myself (I&rsquo;m neither a game nor a web programmer). ChatGPT opens the door to implementing your pet project. It is now not just a helper but a powerful software development tool. I strongly encourage you to try it yourself to get a taste of new opportunities and to build up your AI usage expertise.</p>
<p>Have fun!</p>]]></content:encoded></item><item><title>ChatGPT has written a game for me! Game of Gravity: Caveman Tumble</title><link>https://konstantin.gladyou.click/posts/2023-10-24-chatgpt-has-written-a-game-for-me-game-of-gravity-caveman-tumble/</link><pubDate>Tue, 24 Oct 2023 10:24:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2023-10-24-chatgpt-has-written-a-game-for-me-game-of-gravity-caveman-tumble/</guid><description>&lt;img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_12010.png" alt="" title=""></description><content:encoded><![CDATA[<img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_12010.png" alt="" title="">
<p>For quite some time I wanted to create a game. Just a simple browser-based JavaScript game with some simple physics simulation in it. But I am not a Front-End developer and when I tried, I got stuck real quick. And now I gave it another try, but with help of <a href="https://chat.openai.com/" target="_blank">ChatGPT</a>. And here it is: <a href="https://d2ekywmdx5fh2l.cloudfront.net/" target="_blank">Game of Gravity: Caveman Tumble</a>.</p>
<p>All of the code came from ChatGPT while I was doing only prompting and copy/pasting its answers. But not only that. Here is the list of what AI did for me:</p>
<ul>
<li>Choice of libraries;</li>
<li>HTML/CSS generation with styling (I just gave the general style I want to see);</li>
<li>Code refactoring;</li>
<li>Images generation (<a href="https://www.midjourney.com/" target="_blank">Midjourney</a> rocks!);</li>
<li>AWS deployment scripts;</li>
<li>Step-by-step guides to connect Google Domains, Analytics, etc.;</li>
<li>Name generation;</li>
<li>Help with debugging;</li>
<li>Utility scripts (e.g. a script to compile application files to be submitted into the chat).</li>
</ul>
<p>Basically everything was written by AI. My role was more of a Technical Product Manager, not a developer. Yes, I had to give really low-level instructions sometime, but overall I was focused on behavior, not the code. And I believe this was critical to make things done. Previously, when I was focused on the code itself it was hard for me to keep in mind the overall application and I did not manage to simplify it enough to manage the development.</p>
<p>What did not go so well? Well, a couple of things:</p>
<ul>
<li>Debugging.</li> While AI did great job fixing well known issues or problems with logic, it stuck when faced a new bug in the physics library. And the bug was really far from trivial (behavior of concave objects moved to non-static after the simulation has started). I had to spend huge amount of efforts to find the root cause and explain it to the Chat so it could create a fix.
<li>HTML/CSS.</li> ChatGPT had a hard time with this part. Maybe because it is too visual and the AI couldn't see the results, but it took many iterations and simplifactions to make the design. Or maybe it's because I don't know enough about HTML/CSS to produce correct requirements here.
<li>AWS CDK version.</li> Not really a problem, but it worth mentioning that ChatGPT always tried to implement everything with CDK v1. I had to ask him every time to produce the v2 code. Sometimes it became some strange mix of different libs, but ChatGPT generally managed to come to the right result.
</ul>
<p>The process was neither quick, nor easy. I was working on it 3 months in my free time and there were 140+ commits in the repo in total. Which I think is ok for the project this size, but still we can&rsquo;t do &lsquo;Push one button — get the result&rsquo; implementation. But I must admit that the initial implementation came really quickly and most of the time was spent on bugfixing and iterational requirements clarification.</p>
<p>I tried several AI tools ChatGPT v3.5, Bard, Llama2, Wizard Coder 34b, but I found out that even small error in the response can easily lead to hours of debugging and the ChatGPT 4 gives the best results. This gives hope that next versions of the AI tools might be even more powerful.</p>
<p>The code of the project can be found <a href="https://github.com/bukov-ka/caveman-tumble">here</a>.</p>]]></content:encoded></item><item><title>Make a Translator with ChatGPT</title><link>https://konstantin.gladyou.click/posts/2023-03-20-make-a-translator-with-chatgpt/</link><pubDate>Mon, 20 Mar 2023 23:20:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2023-03-20-make-a-translator-with-chatgpt/</guid><description>&lt;center>&lt;img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_11521.png">&lt;/center>
Have you tried ChatGPT as a development assistant? If not I am strongly recommend you to try. It is amazing. And here is a story of my first stab on the technology.</description><content:encoded><![CDATA[<center><img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_11521.png"></center>
Have you tried ChatGPT as a development assistant? If not I am strongly recommend you to try. It is amazing. And here is a story of my first stab on the technology.
<p>For quite some time I wanted to translate a book I&rsquo;ve written to English. The book is created in LaTeX and has quite a bit of special formatting instructions, it is placed in many files and I always thought it is an extremely hard task even to get some variant for future work.</p>
<p>I decided to give at a shot and asked ChatGPT to create a console .NET program which would use ChatGPT API for translation. As a result I got a console program. It used an outdated API version and .NET version, but overall it looked good. Actually I ran the same request 3 times to get 3 different versions of the code and chose the best one.</p>
<p>Instead of trying to get the whole program out of the AI, I&rsquo;ve send the input and output JSONs and asked to generated C# models. They have small issues like using restricted property names, but I just sent the errors to the chat and got the corrected code.</p>
<p>Running the code revealed API limitation: it does not support parallel requests. Again, one query and I&rsquo;ve got a sequential version. By the way, for small pieces of code it was easier to use GitHub Copilot, another great AI tool which has a great integration with Visual Studio Code.</p>
<p>In about an hour I had a version which produced translation, again via ChatGPT. Of course it has some issues. For one story in the book ChatGPT even put different version of the ending along with an actual translation. But it is amazing. Using one general API I have created a program and translated a book. And the most important thing: it was fun.</p>
<p>You can check the code here: <a href="https://github.com/bukov-ka/articles_code/tree/chatGPT">link</a>.</p>
<p>The most awesome things of programming with ChatGPT:</p>
<ul>
<li>It's one API for any task. You just formulate what you need in a natural language and that's it;</li>
<li>You can easily hand to ChatGPT the most boring part of coding;</li>
<li>Having a ChatGPT is like having a teammate for pair programming, you can get a piece of advice or a different implementation of an algorithm;</li>
<li>You are getting a feeling that the future has come.</li>
</ul>]]></content:encoded></item><item><title>Tchisla Solution Finder</title><link>https://konstantin.gladyou.click/posts/2022-07-19-tchisla-solution-finder/</link><pubDate>Tue, 19 Jul 2022 16:17:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2022-07-19-tchisla-solution-finder/</guid><description>&lt;p>There is a beautiful math puzzle game called &lt;a href="https://apps.apple.com/us/app/tchisla-number-puzzle/id1100623105" target="_blank">Tchisla&lt;/a>. The goal is to express a number with a single digit and math operations, using as few digit occurencies as possible.&lt;/p></description><content:encoded><![CDATA[<p>There is a beautiful math puzzle game called <a href="https://apps.apple.com/us/app/tchisla-number-puzzle/id1100623105" target="_blank">Tchisla</a>. The goal is to express a number with a single digit and math operations, using as few digit occurencies as possible.</p>
<p>For example, here is the optimal solution to express &lsquo;100&rsquo; using &lsquo;2&rsquo;s:</p>
<center><pre>100=((22-2)/2)^2</pre></center>
It requires only 5 digits '2' which is the minimal possible number of twos. You could use 6 '2's, but it is not the minimum: 
<center><pre>2 * (2 + 2 * (2 + 22))</pre></center>
<p>A friend of mine struggled expressing &lsquo;1024&rsquo; with only 3 eights and I thought that it is a good 1 hour task which I could use in interviews. The idea is quite simple: we will generate all possible expressions and then evaluate each of them.</p>
<p>It is pretty obvious that the number of possible expressions is infinite. Even using one digit &lsquo;2&rsquo; we can use indefinite number of operators, like: <center><pre>sqrt(2), sqrt(sqrt(2)), sqrt(sqrt(2!)), &hellip;<pre></center>
We will just ignore that fact, because we do not want to cover all theorhetically possible variants, we just need to find a solution.</p>
<p>The first step is to create a class to represent one node of the evaluation tree:</p>
<pre style="background:#1E1E1E">

<span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">class</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">Node</span>
<span style="color:#D4D4D4;">{</span>
<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">int</span><span style="color:#D4D4D4;">? </span><span style="color:#9CDCFE;">val</span><span style="color:#D4D4D4;">;</span>
<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">Node</span><span style="color:#D4D4D4;">? </span><span style="color:#9CDCFE;">left</span><span style="color:#D4D4D4;">;</span>
<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">Node</span><span style="color:#D4D4D4;">? </span><span style="color:#9CDCFE;">right</span><span style="color:#D4D4D4;">;</span>

<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">Node</span><span style="color:#D4D4D4;">(</span><span style="color:#569CD6;">int</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">val</span><span style="color:#D4D4D4;">)</span>
<span style="color:#D4D4D4;">      {</span>
<span style="color:#D4D4D4;">            </span><span style="color:#569CD6;">this</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">val</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">val</span><span style="color:#D4D4D4;">;</span>
<span style="color:#D4D4D4;">      }</span>

<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">Node</span><span style="color:#D4D4D4;">(</span><span style="color:#4EC9B0;">Node</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">left</span><span style="color:#D4D4D4;">, </span><span style="color:#4EC9B0;">Node</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">right</span><span style="color:#D4D4D4;">)</span>
<span style="color:#D4D4D4;">      {</span>
<span style="color:#D4D4D4;">            </span><span style="color:#569CD6;">this</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">left</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">left</span><span style="color:#D4D4D4;">;</span>
<span style="color:#D4D4D4;">            </span><span style="color:#569CD6;">this</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">right</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">right</span><span style="color:#D4D4D4;">;</span>
<span style="color:#D4D4D4;">      }</span>

<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">string</span><span style="color:#D4D4D4;">[] </span><span style="color:#DCDCAA;">GetVariants</span><span style="color:#D4D4D4;">()</span>
<span style="color:#D4D4D4;">      {</span>
<span style="color:#D4D4D4;">            </span><span style="color:#569CD6;">string</span><span style="color:#D4D4D4;">[] </span><span style="color:#9CDCFE;">prefixes</span><span style="color:#D4D4D4;"> = </span><span style="color:#569CD6;">new</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">string</span><span style="color:#D4D4D4;">[] { </span><span style="color:#CE9178;">""</span><span style="color:#D4D4D4;">, </span><span style="color:#CE9178;">"Sqrt"</span><span style="color:#D4D4D4;">, </span><span style="color:#CE9178;">"-"</span><span style="color:#D4D4D4;">};</span>
<span style="color:#D4D4D4;">            </span><span style="color:#C586C0;">if</span><span style="color:#D4D4D4;"> (</span><span style="color:#9CDCFE;">val</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">HasValue</span><span style="color:#D4D4D4;">)</span>
<span style="color:#D4D4D4;">            {</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#C586C0;">return</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">prefixes</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">Select</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">s</span><span style="color:#D4D4D4;"> =&gt; </span><span style="color:#CE9178;">$"{</span><span style="color:#9CDCFE;">s</span><span style="color:#CE9178;">}({</span><span style="color:#9CDCFE;">val</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">Value</span><span style="color:#CE9178;">})"</span><span style="color:#D4D4D4;">).</span><span style="color:#DCDCAA;">ToArray</span><span style="color:#D4D4D4;">();</span>
<span style="color:#D4D4D4;">            }</span>
<span style="color:#D4D4D4;">            </span><span style="color:#C586C0;">else</span>
<span style="color:#D4D4D4;">            {</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">leftVariants</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">left</span><span style="color:#D4D4D4;">!.</span><span style="color:#DCDCAA;">GetVariants</span><span style="color:#D4D4D4;">();</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">rightVariants</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">right</span><span style="color:#D4D4D4;">!.</span><span style="color:#DCDCAA;">GetVariants</span><span style="color:#D4D4D4;">();</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#C586C0;">return</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">prefixes</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">SelectMany</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">s</span><span style="color:#D4D4D4;"> =&gt; </span><span style="color:#9CDCFE;">leftVariants</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">SelectMany</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">l</span><span style="color:#D4D4D4;"> =&gt; </span><span style="color:#9CDCFE;">rightVariants</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">SelectMany</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">r</span><span style="color:#D4D4D4;"> =&gt;</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#569CD6;">new</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">string</span><span style="color:#D4D4D4;">[]{</span>
<span style="color:#D4D4D4;">                        </span><span style="color:#CE9178;">$"{</span><span style="color:#9CDCFE;">s</span><span style="color:#CE9178;">}({</span><span style="color:#9CDCFE;">l</span><span style="color:#CE9178;">}+{</span><span style="color:#9CDCFE;">r</span><span style="color:#CE9178;">})"</span><span style="color:#D4D4D4;">,</span>
<span style="color:#D4D4D4;">                        </span><span style="color:#CE9178;">$"{</span><span style="color:#9CDCFE;">s</span><span style="color:#CE9178;">}({</span><span style="color:#9CDCFE;">l</span><span style="color:#CE9178;">}-{</span><span style="color:#9CDCFE;">r</span><span style="color:#CE9178;">})"</span><span style="color:#D4D4D4;">,</span>
<span style="color:#D4D4D4;">                        </span><span style="color:#CE9178;">$"{</span><span style="color:#9CDCFE;">s</span><span style="color:#CE9178;">}({</span><span style="color:#9CDCFE;">l</span><span style="color:#CE9178;">}*{</span><span style="color:#9CDCFE;">r</span><span style="color:#CE9178;">})"</span><span style="color:#D4D4D4;">,</span>
<span style="color:#D4D4D4;">                        </span><span style="color:#CE9178;">$"{</span><span style="color:#9CDCFE;">s</span><span style="color:#CE9178;">}({</span><span style="color:#9CDCFE;">l</span><span style="color:#CE9178;">}/{</span><span style="color:#9CDCFE;">r</span><span style="color:#CE9178;">})"</span><span style="color:#D4D4D4;">,</span>
<span style="color:#D4D4D4;">                        </span><span style="color:#CE9178;">$"{</span><span style="color:#9CDCFE;">s</span><span style="color:#CE9178;">}(Pow({</span><span style="color:#9CDCFE;">l</span><span style="color:#CE9178;">},{</span><span style="color:#9CDCFE;">r</span><span style="color:#CE9178;">}))"</span><span style="color:#D4D4D4;">,</span>
<span style="color:#D4D4D4;">                        })</span>
<span style="color:#D4D4D4;">            )).</span><span style="color:#DCDCAA;">ToArray</span><span style="color:#D4D4D4;">();</span>
<span style="color:#D4D4D4;">            }</span>
<span style="color:#D4D4D4;">      }</span>

<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">override</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">string</span><span style="color:#D4D4D4;"> </span><span style="color:#DCDCAA;">ToString</span><span style="color:#D4D4D4;">()</span>
<span style="color:#D4D4D4;">      {</span>
<span style="color:#D4D4D4;">            </span><span style="color:#C586C0;">if</span><span style="color:#D4D4D4;"> (</span><span style="color:#9CDCFE;">val</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">HasValue</span><span style="color:#D4D4D4;">)</span>
<span style="color:#D4D4D4;">            {</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#C586C0;">return</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">val</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">Value</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">ToString</span><span style="color:#D4D4D4;">();</span>
<span style="color:#D4D4D4;">            }</span>
<span style="color:#D4D4D4;">            </span><span style="color:#C586C0;">else</span>
<span style="color:#D4D4D4;">            {</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#C586C0;">return</span><span style="color:#D4D4D4;"> </span><span style="color:#CE9178;">$"({</span><span style="color:#9CDCFE;">left</span><span style="color:#D4D4D4;">!.</span><span style="color:#DCDCAA;">ToString</span><span style="color:#CE9178;">()}-{</span><span style="color:#9CDCFE;">right</span><span style="color:#D4D4D4;">!.</span><span style="color:#DCDCAA;">ToString</span><span style="color:#CE9178;">()})"</span><span style="color:#D4D4D4;">;</span>
<span style="color:#D4D4D4;">            }</span>
<span style="color:#D4D4D4;">      }</span>
<span style="color:#D4D4D4;">}</span>
</pre>
<p>The Node class can contain either an integer value or two operands, left and right. The most important method is GetVariants(), which produces all possible expression variants for the given node. It combines all possible one-operand functions (-val, sqrt(val)) with all possible two-operand functions (val1+val2, val1*val2, pow(val1,val2)) and returns all the possible string expression corresponding to the given tree.</p>
<p>Let&rsquo;s write the tree generator which will produce all possible expression trees for the given string of digits:</p>
<pre style="background:#1E1E1E">
<span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">class</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">TreeGenerator</span>
<span style="color:#D4D4D4;">{</span>
<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">IEnumerable</span><span style="color:#D4D4D4;">&lt;</span><span style="color:#4EC9B0;">Node</span><span style="color:#D4D4D4;">&gt; </span><span style="color:#DCDCAA;">Generate</span><span style="color:#D4D4D4;">(</span><span style="color:#569CD6;">char</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">digit</span><span style="color:#D4D4D4;">, </span><span style="color:#569CD6;">int</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">count</span><span style="color:#D4D4D4;">)</span>
<span style="color:#D4D4D4;">      {</span>
<span style="color:#D4D4D4;">            </span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">str</span><span style="color:#D4D4D4;"> = </span><span style="color:#569CD6;">new</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">string</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">digit</span><span style="color:#D4D4D4;">, </span><span style="color:#9CDCFE;">count</span><span style="color:#D4D4D4;">);</span>
<span style="color:#D4D4D4;">            </span><span style="color:#C586C0;">return</span><span style="color:#D4D4D4;"> </span><span style="color:#DCDCAA;">GetNodes</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">str</span><span style="color:#D4D4D4;">);</span>
<span style="color:#D4D4D4;">      }</span>

<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">IEnumerable</span><span style="color:#D4D4D4;">&lt;</span><span style="color:#4EC9B0;">Node</span><span style="color:#D4D4D4;">&gt; </span><span style="color:#DCDCAA;">GetNodes</span><span style="color:#D4D4D4;">(</span><span style="color:#569CD6;">string</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">str</span><span style="color:#D4D4D4;">)</span>
<span style="color:#D4D4D4;">      {</span>
<span style="color:#D4D4D4;">            </span><span style="color:#C586C0;">yield</span><span style="color:#D4D4D4;"> </span><span style="color:#C586C0;">return</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">new</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">Node</span><span style="color:#D4D4D4;">(</span><span style="color:#4EC9B0;">Convert</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">ToInt32</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">str</span><span style="color:#D4D4D4;">));</span>
<span style="color:#D4D4D4;">            </span><span style="color:#C586C0;">for</span><span style="color:#D4D4D4;"> (</span><span style="color:#569CD6;">int</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">i</span><span style="color:#D4D4D4;"> = </span><span style="color:#B5CEA8;">1</span><span style="color:#D4D4D4;">; </span><span style="color:#9CDCFE;">i</span><span style="color:#D4D4D4;"> &lt; </span><span style="color:#9CDCFE;">str</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">Length</span><span style="color:#D4D4D4;">; </span><span style="color:#9CDCFE;">i</span><span style="color:#D4D4D4;">++)</span>
<span style="color:#D4D4D4;">            {</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">left</span><span style="color:#D4D4D4;"> = </span><span style="color:#DCDCAA;">GetNodes</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">str</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">Substring</span><span style="color:#D4D4D4;">(</span><span style="color:#B5CEA8;">0</span><span style="color:#D4D4D4;">, </span><span style="color:#9CDCFE;">i</span><span style="color:#D4D4D4;">));</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">right</span><span style="color:#D4D4D4;"> = </span><span style="color:#DCDCAA;">GetNodes</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">str</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">Substring</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">i</span><span style="color:#D4D4D4;">));</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#C586C0;">foreach</span><span style="color:#D4D4D4;"> (</span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">l</span><span style="color:#D4D4D4;"> </span><span style="color:#C586C0;">in</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">left</span><span style="color:#D4D4D4;">)</span>
<span style="color:#D4D4D4;">                  {</span>
<span style="color:#D4D4D4;">                        </span><span style="color:#C586C0;">foreach</span><span style="color:#D4D4D4;"> (</span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">r</span><span style="color:#D4D4D4;"> </span><span style="color:#C586C0;">in</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">right</span><span style="color:#D4D4D4;">)</span>
<span style="color:#D4D4D4;">                        {</span>
<span style="color:#D4D4D4;">                              </span><span style="color:#C586C0;">yield</span><span style="color:#D4D4D4;"> </span><span style="color:#C586C0;">return</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">new</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">Node</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">l</span><span style="color:#D4D4D4;">, </span><span style="color:#9CDCFE;">r</span><span style="color:#D4D4D4;">);</span>
<span style="color:#D4D4D4;">                        }</span>
<span style="color:#D4D4D4;">                  }</span>
<span style="color:#D4D4D4;">            }</span>

<span style="color:#D4D4D4;">      }</span>
<span style="color:#D4D4D4;">}</span>
</pre>
<p>The GetNodes() methods splits the input string in all possible ways and passed it recursively for the future processing.</p>
<p>And now we are ready for the final step: evaluate all the possible expressions and select only those which give us the right answer:</p>
<pre style="background:#1E1E1E">

<span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">class</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">Node</span>
<span style="color:#D4D4D4;">{</span>
<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">int</span><span style="color:#D4D4D4;">? </span><span style="color:#9CDCFE;">val</span><span style="color:#D4D4D4;">;</span>
<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">Node</span><span style="color:#D4D4D4;">? </span><span style="color:#9CDCFE;">left</span><span style="color:#D4D4D4;">;</span>
<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">Node</span><span style="color:#D4D4D4;">? </span><span style="color:#9CDCFE;">right</span><span style="color:#D4D4D4;">;</span>

<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">Node</span><span style="color:#D4D4D4;">(</span><span style="color:#569CD6;">int</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">val</span><span style="color:#D4D4D4;">)</span>
<span style="color:#D4D4D4;">      {</span>
<span style="color:#D4D4D4;">            </span><span style="color:#569CD6;">this</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">val</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">val</span><span style="color:#D4D4D4;">;</span>
<span style="color:#D4D4D4;">      }</span>

<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">Node</span><span style="color:#D4D4D4;">(</span><span style="color:#4EC9B0;">Node</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">left</span><span style="color:#D4D4D4;">, </span><span style="color:#4EC9B0;">Node</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">right</span><span style="color:#D4D4D4;">)</span>
<span style="color:#D4D4D4;">      {</span>
<span style="color:#D4D4D4;">            </span><span style="color:#569CD6;">this</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">left</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">left</span><span style="color:#D4D4D4;">;</span>
<span style="color:#D4D4D4;">            </span><span style="color:#569CD6;">this</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">right</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">right</span><span style="color:#D4D4D4;">;</span>
<span style="color:#D4D4D4;">      }</span>

<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">string</span><span style="color:#D4D4D4;">[] </span><span style="color:#DCDCAA;">GetVariants</span><span style="color:#D4D4D4;">()</span>
<span style="color:#D4D4D4;">      {</span>
<span style="color:#D4D4D4;">            </span><span style="color:#569CD6;">string</span><span style="color:#D4D4D4;">[] </span><span style="color:#9CDCFE;">prefixes</span><span style="color:#D4D4D4;"> = </span><span style="color:#569CD6;">new</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">string</span><span style="color:#D4D4D4;">[] { </span><span style="color:#CE9178;">""</span><span style="color:#D4D4D4;">, </span><span style="color:#CE9178;">"Sqrt"</span><span style="color:#D4D4D4;">, </span><span style="color:#CE9178;">"-"</span><span style="color:#D4D4D4;">};</span>
<span style="color:#D4D4D4;">            </span><span style="color:#C586C0;">if</span><span style="color:#D4D4D4;"> (</span><span style="color:#9CDCFE;">val</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">HasValue</span><span style="color:#D4D4D4;">)</span>
<span style="color:#D4D4D4;">            {</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#C586C0;">return</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">prefixes</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">Select</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">s</span><span style="color:#D4D4D4;"> =&gt; </span><span style="color:#CE9178;">$"{</span><span style="color:#9CDCFE;">s</span><span style="color:#CE9178;">}({</span><span style="color:#9CDCFE;">val</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">Value</span><span style="color:#CE9178;">})"</span><span style="color:#D4D4D4;">).</span><span style="color:#DCDCAA;">ToArray</span><span style="color:#D4D4D4;">();</span>
<span style="color:#D4D4D4;">            }</span>
<span style="color:#D4D4D4;">            </span><span style="color:#C586C0;">else</span>
<span style="color:#D4D4D4;">            {</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">leftVariants</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">left</span><span style="color:#D4D4D4;">!.</span><span style="color:#DCDCAA;">GetVariants</span><span style="color:#D4D4D4;">();</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">rightVariants</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">right</span><span style="color:#D4D4D4;">!.</span><span style="color:#DCDCAA;">GetVariants</span><span style="color:#D4D4D4;">();</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#C586C0;">return</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">prefixes</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">SelectMany</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">s</span><span style="color:#D4D4D4;"> =&gt; </span><span style="color:#9CDCFE;">leftVariants</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">SelectMany</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">l</span><span style="color:#D4D4D4;"> =&gt; </span><span style="color:#9CDCFE;">rightVariants</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">SelectMany</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">r</span><span style="color:#D4D4D4;"> =&gt;</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#569CD6;">new</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">string</span><span style="color:#D4D4D4;">[]{</span>
<span style="color:#D4D4D4;">                        </span><span style="color:#CE9178;">$"{</span><span style="color:#9CDCFE;">s</span><span style="color:#CE9178;">}({</span><span style="color:#9CDCFE;">l</span><span style="color:#CE9178;">}+{</span><span style="color:#9CDCFE;">r</span><span style="color:#CE9178;">})"</span><span style="color:#D4D4D4;">,</span>
<span style="color:#D4D4D4;">                        </span><span style="color:#CE9178;">$"{</span><span style="color:#9CDCFE;">s</span><span style="color:#CE9178;">}({</span><span style="color:#9CDCFE;">l</span><span style="color:#CE9178;">}-{</span><span style="color:#9CDCFE;">r</span><span style="color:#CE9178;">})"</span><span style="color:#D4D4D4;">,</span>
<span style="color:#D4D4D4;">                        </span><span style="color:#CE9178;">$"{</span><span style="color:#9CDCFE;">s</span><span style="color:#CE9178;">}({</span><span style="color:#9CDCFE;">l</span><span style="color:#CE9178;">}*{</span><span style="color:#9CDCFE;">r</span><span style="color:#CE9178;">})"</span><span style="color:#D4D4D4;">,</span>
<span style="color:#D4D4D4;">                        </span><span style="color:#CE9178;">$"{</span><span style="color:#9CDCFE;">s</span><span style="color:#CE9178;">}({</span><span style="color:#9CDCFE;">l</span><span style="color:#CE9178;">}/{</span><span style="color:#9CDCFE;">r</span><span style="color:#CE9178;">})"</span><span style="color:#D4D4D4;">,</span>
<span style="color:#D4D4D4;">                        </span><span style="color:#CE9178;">$"{</span><span style="color:#9CDCFE;">s</span><span style="color:#CE9178;">}(Pow({</span><span style="color:#9CDCFE;">l</span><span style="color:#CE9178;">},{</span><span style="color:#9CDCFE;">r</span><span style="color:#CE9178;">}))"</span><span style="color:#D4D4D4;">,</span>
<span style="color:#D4D4D4;">                        })</span>
<span style="color:#D4D4D4;">            )).</span><span style="color:#DCDCAA;">ToArray</span><span style="color:#D4D4D4;">();</span>
<span style="color:#D4D4D4;">            }</span>
<span style="color:#D4D4D4;">      }</span>

<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">override</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">string</span><span style="color:#D4D4D4;"> </span><span style="color:#DCDCAA;">ToString</span><span style="color:#D4D4D4;">()</span>
<span style="color:#D4D4D4;">      {</span>
<span style="color:#D4D4D4;">            </span><span style="color:#C586C0;">if</span><span style="color:#D4D4D4;"> (</span><span style="color:#9CDCFE;">val</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">HasValue</span><span style="color:#D4D4D4;">)</span>
<span style="color:#D4D4D4;">            {</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#C586C0;">return</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">val</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">Value</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">ToString</span><span style="color:#D4D4D4;">();</span>
<span style="color:#D4D4D4;">            }</span>
<span style="color:#D4D4D4;">            </span><span style="color:#C586C0;">else</span>
<span style="color:#D4D4D4;">            {</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#C586C0;">return</span><span style="color:#D4D4D4;"> </span><span style="color:#CE9178;">$"({</span><span style="color:#9CDCFE;">left</span><span style="color:#D4D4D4;">!.</span><span style="color:#DCDCAA;">ToString</span><span style="color:#CE9178;">()}-{</span><span style="color:#9CDCFE;">right</span><span style="color:#D4D4D4;">!.</span><span style="color:#DCDCAA;">ToString</span><span style="color:#CE9178;">()})"</span><span style="color:#D4D4D4;">;</span>
<span style="color:#D4D4D4;">            }</span>
<span style="color:#D4D4D4;">      }</span>
<span style="color:#D4D4D4;">}</span>
<span style="color:#569CD6;">using</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">NCalc</span><span style="color:#D4D4D4;">;</span>

<span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">class</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">Calculator</span>
<span style="color:#D4D4D4;">{</span>
<span style="color:#D4D4D4;">      </span><span style="color:#4EC9B0;">Node</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">root</span><span style="color:#D4D4D4;">;</span>
<span style="color:#D4D4D4;">      </span><span style="color:#6A9955;">/// &lt;summary&gt;</span>
<span style="color:#D4D4D4;">      </span><span style="color:#6A9955;">/// Initializes a new instance of the &lt;see cref="</span><span style="color:#4EC9B0;">Calculator</span><span style="color:#6A9955;">"/&gt; class.</span>
<span style="color:#D4D4D4;">      </span><span style="color:#6A9955;">/// &lt;/summary&gt;</span>
<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">Calculator</span><span style="color:#D4D4D4;">(</span><span style="color:#4EC9B0;">Node</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">node</span><span style="color:#D4D4D4;">)</span>
<span style="color:#D4D4D4;">      {</span>
<span style="color:#D4D4D4;">            </span><span style="color:#569CD6;">this</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">root</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">node</span><span style="color:#D4D4D4;">;</span>
<span style="color:#D4D4D4;">      }</span>

<span style="color:#D4D4D4;">      </span><span style="color:#6A9955;">/// &lt;summary&gt;</span>
<span style="color:#D4D4D4;">      </span><span style="color:#6A9955;">/// Get all possible variants to get the result.</span>
<span style="color:#D4D4D4;">      </span><span style="color:#6A9955;">/// &lt;/summary&gt;</span>
<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">IEnumerable</span><span style="color:#D4D4D4;">&lt;</span><span style="color:#569CD6;">string</span><span style="color:#D4D4D4;">&gt; </span><span style="color:#DCDCAA;">Calculate</span><span style="color:#D4D4D4;">(</span><span style="color:#569CD6;">int</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">res</span><span style="color:#D4D4D4;">)</span>
<span style="color:#D4D4D4;">      {</span>
<span style="color:#D4D4D4;">            </span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">resultTarget</span><span style="color:#D4D4D4;"> = </span><span style="color:#4EC9B0;">Convert</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">ToDouble</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">res</span><span style="color:#D4D4D4;">);</span>
<span style="color:#D4D4D4;">            </span><span style="color:#C586C0;">foreach</span><span style="color:#D4D4D4;"> (</span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">v</span><span style="color:#D4D4D4;"> </span><span style="color:#C586C0;">in</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">this</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">root</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">GetVariants</span><span style="color:#D4D4D4;">())</span>
<span style="color:#D4D4D4;">            {</span>

<span style="color:#D4D4D4;">                  </span><span style="color:#4EC9B0;">Expression</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">e</span><span style="color:#D4D4D4;"> = </span><span style="color:#569CD6;">new</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">Expression</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">v</span><span style="color:#D4D4D4;">, </span><span style="color:#4EC9B0;">NCalc</span><span style="color:#D4D4D4;">.</span><span style="color:#4EC9B0;">EvaluateOptions</span><span style="color:#D4D4D4;">.</span><span style="color:#4FC1FF;">NoCache</span><span style="color:#D4D4D4;">);</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#C586C0;">if</span><span style="color:#D4D4D4;"> (!</span><span style="color:#9CDCFE;">e</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">HasErrors</span><span style="color:#D4D4D4;">())</span>
<span style="color:#D4D4D4;">                  {</span>
<span style="color:#D4D4D4;">                        </span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">resultCurrent</span><span style="color:#D4D4D4;"> = </span><span style="color:#4EC9B0;">Math</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">Round</span><span style="color:#D4D4D4;">(</span><span style="color:#4EC9B0;">Convert</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">ToDouble</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">e</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">Evaluate</span><span style="color:#D4D4D4;">()), </span><span style="color:#B5CEA8;">4</span><span style="color:#D4D4D4;">);</span>
<span style="color:#D4D4D4;">                        </span><span style="color:#C586C0;">if</span><span style="color:#D4D4D4;"> (</span><span style="color:#4EC9B0;">Math</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">Abs</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">resultCurrent</span><span style="color:#D4D4D4;"> - </span><span style="color:#9CDCFE;">resultTarget</span><span style="color:#D4D4D4;">) &lt; </span><span style="color:#B5CEA8;">0.00001</span><span style="color:#D4D4D4;">)</span>
<span style="color:#D4D4D4;">                        {</span>
<span style="color:#D4D4D4;">                              </span><span style="color:#C586C0;">yield</span><span style="color:#D4D4D4;"> </span><span style="color:#C586C0;">return</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">v</span><span style="color:#D4D4D4;">;</span>
<span style="color:#D4D4D4;">                        }</span>
<span style="color:#D4D4D4;">                  }</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#C586C0;">else</span>
<span style="color:#D4D4D4;">                  {</span>
<span style="color:#D4D4D4;">                        </span><span style="color:#4EC9B0;">Console</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">WriteLine</span><span style="color:#D4D4D4;">(</span><span style="color:#CE9178;">$"Error: {</span><span style="color:#9CDCFE;">e</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">Error</span><span style="color:#CE9178;">}"</span><span style="color:#D4D4D4;">);</span>
<span style="color:#D4D4D4;">                        </span><span style="color:#4EC9B0;">Console</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">WriteLine</span><span style="color:#D4D4D4;">(</span><span style="color:#CE9178;">$"Input: {</span><span style="color:#9CDCFE;">v</span><span style="color:#CE9178;">}"</span><span style="color:#D4D4D4;">);</span>
<span style="color:#D4D4D4;">                  }</span>

<span style="color:#D4D4D4;">            }</span>
<span style="color:#D4D4D4;">      }</span>

<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">override</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">string</span><span style="color:#D4D4D4;"> </span><span style="color:#DCDCAA;">ToString</span><span style="color:#D4D4D4;">()</span>
<span style="color:#D4D4D4;">      {</span>
<span style="color:#D4D4D4;">            </span><span style="color:#C586C0;">return</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">this</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">root</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">ToString</span><span style="color:#D4D4D4;">();</span>
<span style="color:#D4D4D4;">      }</span>
<span style="color:#D4D4D4;">}</span>
</pre>
<p>We use the NCalc library, which evaluates a string and give us a result. The only trick here is the comparison. Since floating points calculations are involved, we have to compare values with some precision. 4 decimal places looks like a good enough approximation for the result.</p>
<p>And the very last point is to run calculation for our task and select the best result:</p>
<pre style="background:#1E1E1E">
<span style="color:#569CD6;">void</span><span style="color:#D4D4D4;"> </span><span style="color:#DCDCAA;">solutions</span><span style="color:#D4D4D4;">(</span><span style="color:#569CD6;">char</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">digit</span><span style="color:#D4D4D4;">, </span><span style="color:#569CD6;">int</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">count</span><span style="color:#D4D4D4;">, </span><span style="color:#569CD6;">int</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">result</span><span style="color:#D4D4D4;">)</span>
<span style="color:#D4D4D4;">{</span>

<span style="color:#D4D4D4;">      </span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">generator</span><span style="color:#D4D4D4;"> = </span><span style="color:#569CD6;">new</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">TreeGenerator</span><span style="color:#D4D4D4;">();</span>
<span style="color:#D4D4D4;">      </span><span style="color:#C586C0;">foreach</span><span style="color:#D4D4D4;"> (</span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">node</span><span style="color:#D4D4D4;"> </span><span style="color:#C586C0;">in</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">generator</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">Generate</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">digit</span><span style="color:#D4D4D4;">, </span><span style="color:#9CDCFE;">count</span><span style="color:#D4D4D4;">))</span>
<span style="color:#D4D4D4;">      {</span>
<span style="color:#D4D4D4;">            </span><span style="color:#4EC9B0;">Calculator</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">calc</span><span style="color:#D4D4D4;"> = </span><span style="color:#569CD6;">new</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">Calculator</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">node</span><span style="color:#D4D4D4;">);</span>
<span style="color:#D4D4D4;">            </span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">res</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">calc</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">Calculate</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">result</span><span style="color:#D4D4D4;">).</span><span style="color:#DCDCAA;">OrderByDescending</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">o</span><span style="color:#D4D4D4;"> =&gt; </span><span style="color:#9CDCFE;">o</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">Length</span><span style="color:#D4D4D4;">).</span><span style="color:#DCDCAA;">ToArray</span><span style="color:#D4D4D4;">();</span>
<span style="color:#D4D4D4;">            </span><span style="color:#C586C0;">foreach</span><span style="color:#D4D4D4;"> (</span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">v</span><span style="color:#D4D4D4;"> </span><span style="color:#C586C0;">in</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">res</span><span style="color:#D4D4D4;">)</span>
<span style="color:#D4D4D4;">            {</span>
<span style="color:#D4D4D4;">                  </span><span style="color:#4EC9B0;">Console</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">WriteLine</span><span style="color:#D4D4D4;">(</span><span style="color:#CE9178;">$"{</span><span style="color:#9CDCFE;">v</span><span style="color:#CE9178;">}"</span><span style="color:#D4D4D4;">);</span>
<span style="color:#D4D4D4;">            }</span>
<span style="color:#D4D4D4;">      }</span>

<span style="color:#D4D4D4;">}</span>
<span style="color:#D4D4D4;">  </span><span style="color:#DCDCAA;">solutions</span><span style="color:#D4D4D4;">(</span><span style="color:#CE9178;">'8'</span><span style="color:#D4D4D4;">, </span><span style="color:#B5CEA8;">3</span><span style="color:#D4D4D4;">, </span><span style="color:#B5CEA8;">1024</span><span style="color:#D4D4D4;">);</span>
<span style="color:#4EC9B0;">Console</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">WriteLine</span><span style="color:#D4D4D4;">(</span><span style="color:#CE9178;">"Finished."</span><span style="color:#D4D4D4;">);</pre>
<p>We get the results ordered by the length of the final expression. And here are the variants:</p>
<center>
<pre>
Sqrt(Pow(-(Sqrt(8)+Sqrt(8)),(8)))
(Pow(Sqrt(Sqrt(8)+Sqrt(8)),(8)))
Sqrt(Pow((Sqrt(8)+Sqrt(8)),(8)))
</pre>
</center>
All of the variants are pretty the same and give us what we need.
The source code is available on <a href="https://github.com/bukov-ka/articles_code/tree/tchisla">GitHub</a>.]]></content:encoded></item><item><title>DynamoDB Design Trainer</title><link>https://konstantin.gladyou.click/posts/2020-07-28-dynamodb-design-trainer/</link><pubDate>Tue, 28 Jul 2020 15:59:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2020-07-28-dynamodb-design-trainer/</guid><description>There is a great deal of confusion around DynamoDB scheme design. People used to SQL are focused on designing DB schema and are thinking about data. But DynamoDB is schemaless and it focuses on action. SQL DB once designed can be used to perform any queries, but DynamoDB is designed to fulfill particular queries efficiently.
To help people master it I created the SQL to DynamoDB Transformation Trainer. You will go through several task.</description><content:encoded><![CDATA[<p><img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_11327.png" width="100px"  alt="DynamoDB" title="DynamoDB" style="float:left; margin:10px"> There is a great deal of confusion around DynamoDB scheme design. People used to SQL are focused on designing DB schema and are thinking about data. But DynamoDB is schemaless and it focuses on action. SQL DB once designed can be used to perform any queries, but DynamoDB is designed to fulfill particular queries efficiently.</p>
<p>To help people master it I created the <a href="https://bukov-ka.github.io/dynamodb/">SQL to DynamoDB Transformation Trainer</a>. You will go through several task. Each contains a SQL DB and set of queries you need to perform over the data. You will design the DynamoDB table and a GSI to perform all the actions with queries over the GSI only.</p>
]]></content:encoded></item><item><title>Amazon Rekognition .NET Core Tutorial</title><link>https://konstantin.gladyou.click/posts/2020-05-19-amazon-rekognition-net-core-tutorial/</link><pubDate>Tue, 19 May 2020 14:44:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2020-05-19-amazon-rekognition-net-core-tutorial/</guid><description>&lt;font style="font-size:12pt;">
&lt;center>
&lt;img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_10365.jpg" alt="" title="">&lt;br>&lt;small style="color:gray;font-size:10pt">Used a photo by &lt;a href="https://unsplash.com/@kazuend">kazuend&lt;/a> on Unsplash&lt;/small>&lt;/center>
Amazon Rekognition engine allows you to enrich your application with some cool AI features and it is very easy for a developer. Unfortunatelly on Internet there is not much examples and tutorials for .NET AWS Rekognition SDK with .Net Core v.3.1 WPF. And it is what I want to fix in this article.</description><content:encoded><![CDATA[<font style="font-size:12pt;">
<center>
<img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_10365.jpg" alt="" title=""><br><small style="color:gray;font-size:10pt">Used a photo by <a href="https://unsplash.com/@kazuend">kazuend</a> on Unsplash</small></center>
Amazon Rekognition engine allows you to enrich your application with some cool AI features and it is very easy for a developer. Unfortunatelly on Internet there is not much examples and tutorials for .NET AWS Rekognition SDK with .Net Core v.3.1 WPF. And it is what I want to fix in this article.
<p>I put code for this tutorial to <a href="https://github.com/bukov-ka/articles_code/tree/rekognition">GitHub</a> and I would like to recommend it to download it and run to see it with your own eyes.</p>
<p>First you need to set up your AWS credentials. I store the credentials in environment variables:
<img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_10528.png" alt="" title="">
In .Net Core those settings are stored in Properties\launchSettings.json. Please make sure this file is safe and your credentials are not exposed through your repository on other way:</p>
<div style="text-align: center;"><pre style="color:black; border:solid 1px darkgray; padding:10px; text-align:left;display: inline-block; background:#1e1e1e">
<span style="color:#D4D4D4;">{
  </span><span style="color:#9CDCFE;">&quot;profiles&quot;</span><span style="color:#D4D4D4;">: {
    </span><span style="color:#9CDCFE;">&quot;DetectFaces&quot;</span><span style="color:#D4D4D4;">: {
      </span><span style="color:#9CDCFE;">&quot;commandName&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;Project&quot;</span><span style="color:#D4D4D4;">,
      </span><span style="color:#9CDCFE;">&quot;environmentVariables&quot;</span><span style="color:#D4D4D4;">: {
        </span><span style="color:#9CDCFE;">&quot;AWS_SECRET_ACCESS_KEY&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&quot;</span><span style="color:#D4D4D4;">,
        </span><span style="color:#9CDCFE;">&quot;AWS_ACCESS_KEY_ID&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;XXXXXXXXXXXXXXXXXXXXXXXXXXXX&quot;</span><span style="color:#D4D4D4;">
      }
    }
  }
}
</pre></div>
<p>Then we need to connect to AWS Rekognition engine. We use AmazonRekognitionClient which is the Amazon.Rekognition namespace. You need to add AWSSDK.Rekognition in the NuGet Package Manager to have access for it. And don&rsquo;t forget using Amazon.Rekognition.Model to get access to all the model classes.</p>
<div style="text-align: center;"><pre style="color:black; border:solid 1px darkgray; padding:10px; text-align:left;display: inline-block; background:#1e1e1e">
<span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">awsAccessKeyId</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">Environment</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">GetEnvironmentVariable</span><span style="color:#D4D4D4;">(</span><span style="color:#CE9178;">&quot;AWS_ACCESS_KEY_ID&quot;</span><span style="color:#D4D4D4;">);
</span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">awsSecretAccessKey</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">Environment</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">GetEnvironmentVariable</span><span style="color:#D4D4D4;">(</span><span style="color:#CE9178;">&quot;AWS_SECRET_ACCESS_KEY&quot;</span><span style="color:#D4D4D4;">);
</span><span style="color:#9CDCFE;">_amazonRekognitionClient</span><span style="color:#D4D4D4;"> = </span><span style="color:#569CD6;">new</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">AmazonRekognitionClient</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">awsAccessKeyId</span><span style="color:#D4D4D4;">, </span><span style="color:#9CDCFE;">awsSecretAccessKey</span><span style="color:#D4D4D4;">, </span><span style="color:#9CDCFE;">RegionEndpoint</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">EUWest2</span><span style="color:#D4D4D4;">);
</pre></div>
Please note that we need to specify a region and not all the regions have Rekognition engine available. Only the following regions are currently supported (you can check via AWS Console whether a region is supported or not):
<ul>
<li>Asia Pacific (Mumbai)</li>
<li>Europe (London)</li>
<li>Europe (Ireland)</li>
<li>Asia Pacific (Seoul)</li>
<li>Asia Pacific (Tokyo)</li>
<li>Asia Pacific (Singapore)</li>
<li>Asia Pacific (Sydney)</li>
<li>Europe (Frankfurt)</li>
<li>US East (N. Virginia)</li>
<li>US East (Ohio)</li>
<li>US West (N. California)</li>
<li>US West (Oregon)</li>
</ul>
<p>Before we can call AWS we need to represent our image as an array of bytes. Image can be converted to bytes with JpegBitmapEncoder and MemoryStream, but you might use any other way, reading a file to a buffer for example:</p>
<div style="text-align: center;"><pre style="color:black; border:solid 1px darkgray; padding:10px; text-align:left;display: inline-block; background:#1e1e1e">
<span style="color:#569CD6;">byte</span><span style="color:#D4D4D4;">[] </span><span style="color:#9CDCFE;">data</span><span style="color:#D4D4D4;">;
</span><span style="color:#4EC9B0;">JpegBitmapEncoder</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">encoder</span><span style="color:#D4D4D4;"> = </span><span style="color:#569CD6;">new</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">JpegBitmapEncoder</span><span style="color:#D4D4D4;">();
</span><span style="color:#9CDCFE;">encoder</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">Frames</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">Add</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">BitmapFrame</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">Create</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">CurrentImage</span><span style="color:#D4D4D4;">));
</span><span style="color:#C586C0;">using</span><span style="color:#D4D4D4;"> (</span><span style="color:#4EC9B0;">MemoryStream</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">ms</span><span style="color:#D4D4D4;"> = </span><span style="color:#569CD6;">new</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">MemoryStream</span><span style="color:#D4D4D4;">())
{
    </span><span style="color:#9CDCFE;">encoder</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">Save</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">ms</span><span style="color:#D4D4D4;">);
    </span><span style="color:#9CDCFE;">data</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">ms</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">ToArray</span><span style="color:#D4D4D4;">();
}</pre></div>
<p>When we have the image bytes the call is simplicity itself:</p>
<div style="text-align: center;"><pre style="color:black; border:solid 1px darkgray; padding:10px; text-align:left;display: inline-block; background:#1e1e1e">
<span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">request</span><span style="color:#D4D4D4;"> = </span><span style="color:#569CD6;">new</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">DetectFacesRequest</span><span style="color:#D4D4D4;"> { </span><span style="color:#9CDCFE;">Image</span><span style="color:#D4D4D4;"> = </span><span style="color:#569CD6;">new</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">Amazon</span><span style="color:#D4D4D4;">.</span><span style="color:#4EC9B0;">Rekognition</span><span style="color:#D4D4D4;">.</span><span style="color:#4EC9B0;">Model</span><span style="color:#D4D4D4;">.</span><span style="color:#4EC9B0;">Image</span><span style="color:#D4D4D4;">() { </span><span style="color:#9CDCFE;">Bytes</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">source</span><span style="color:#D4D4D4;"> }, </span><span style="color:#9CDCFE;">Attributes</span><span style="color:#D4D4D4;"> = </span><span style="color:#569CD6;">new</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">List</span><span style="color:#D4D4D4;">&lt;</span><span style="color:#569CD6;">string</span><span style="color:#D4D4D4;">&gt; { </span><span style="color:#CE9178;">&quot;ALL&quot;</span><span style="color:#D4D4D4;"> } };
</span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">response</span><span style="color:#D4D4D4;"> = </span><span style="color:#569CD6;">await</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">_amazonRekognitionClient</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">DetectFacesAsync</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">request</span><span style="color:#D4D4D4;">);
</span><span style="color:#569CD6;">this</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">faceDetails</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">response</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">FaceDetails</span><span style="color:#D4D4D4;">;</pre></div>
I recommend you to serialize the Rekognition response and take a look into it's fields. It is really usefull to know what you get from the service:
<lj-spoiler title="JSON Rekognition response">
<div style="text-align: center;"><pre style="color:black; border:solid 1px darkgray; padding:10px; text-align:left;display: inline-block; background:#1e1e1e">
<span style="color:#D4D4D4;">{
    </span><span style="color:#9CDCFE;">&quot;FaceDetails&quot;</span><span style="color:#D4D4D4;">: [
        {
            </span><span style="color:#9CDCFE;">&quot;AgeRange&quot;</span><span style="color:#D4D4D4;">: {
                </span><span style="color:#9CDCFE;">&quot;High&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">33</span><span style="color:#D4D4D4;">,
                </span><span style="color:#9CDCFE;">&quot;Low&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">21</span><span style="color:#D4D4D4;">
            },
            </span><span style="color:#9CDCFE;">&quot;Beard&quot;</span><span style="color:#D4D4D4;">: {
                </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">93.551346</span><span style="color:#D4D4D4;">,
                </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#569CD6;">true</span><span style="color:#D4D4D4;">
            },
            </span><span style="color:#9CDCFE;">&quot;BoundingBox&quot;</span><span style="color:#D4D4D4;">: {
                </span><span style="color:#9CDCFE;">&quot;Height&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.5318261</span><span style="color:#D4D4D4;">,
                </span><span style="color:#9CDCFE;">&quot;Left&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.38189748</span><span style="color:#D4D4D4;">,
                </span><span style="color:#9CDCFE;">&quot;Top&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.08973662</span><span style="color:#D4D4D4;">,
                </span><span style="color:#9CDCFE;">&quot;Width&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.30684954</span><span style="color:#D4D4D4;">
            },
            </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">100.0</span><span style="color:#D4D4D4;">,
            </span><span style="color:#9CDCFE;">&quot;Emotions&quot;</span><span style="color:#D4D4D4;">: [
                {
                    </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.8001142</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;ANGRY&quot;</span><span style="color:#D4D4D4;">
                    }
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">86.822525</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;CALM&quot;</span><span style="color:#D4D4D4;">
                    }
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">1.8258944</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;SURPRISED&quot;</span><span style="color:#D4D4D4;">
                    }
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">1.0853829</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;HAPPY&quot;</span><span style="color:#D4D4D4;">
                    }
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">3.3511856</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;SAD&quot;</span><span style="color:#D4D4D4;">
                    }
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.12456241</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;DISGUSTED&quot;</span><span style="color:#D4D4D4;">
                    }
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">5.7627077</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;CONFUSED&quot;</span><span style="color:#D4D4D4;">
                    }
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.22763538</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;FEAR&quot;</span><span style="color:#D4D4D4;">
                    }
                }
            ],
            </span><span style="color:#9CDCFE;">&quot;Eyeglasses&quot;</span><span style="color:#D4D4D4;">: {
                </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">97.766525</span><span style="color:#D4D4D4;">,
                </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#569CD6;">false</span><span style="color:#D4D4D4;">
            },
            </span><span style="color:#9CDCFE;">&quot;EyesOpen&quot;</span><span style="color:#D4D4D4;">: {
                </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">92.13934</span><span style="color:#D4D4D4;">,
                </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#569CD6;">true</span><span style="color:#D4D4D4;">
            },
            </span><span style="color:#9CDCFE;">&quot;Gender&quot;</span><span style="color:#D4D4D4;">: {
                </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">99.02347</span><span style="color:#D4D4D4;">,
                </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: {
                    </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;Male&quot;</span><span style="color:#D4D4D4;">
                }
            },
            </span><span style="color:#9CDCFE;">&quot;Landmarks&quot;</span><span style="color:#D4D4D4;">: [
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;eyeLeft&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.4398567</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.26566792</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;eyeRight&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.57429</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.26926404</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;mouthLeft&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.44999045</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.4615153</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;mouthRight&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.5613504</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.46461004</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;nose&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.50196356</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.37576458</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;leftEyeBrowLeft&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.3901617</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.21878067</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;leftEyeBrowRight&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.46625593</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.2105012</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;leftEyeBrowUp&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.42817318</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.19923115</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;rightEyeBrowLeft&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.54525125</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.21237388</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;rightEyeBrowRight&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.62924606</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.22454414</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;rightEyeBrowUp&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.5863404</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.20254561</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;leftEyeLeft&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.41776064</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.26350778</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;leftEyeRight&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.4667122</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.26807654</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;leftEyeUp&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.4400822</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.25660035</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;leftEyeDown&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.44101533</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.27413929</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;rightEyeLeft&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.5465879</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.27004254</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;rightEyeRight&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.5967773</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.26796222</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;rightEyeUp&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.5728472</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.25988844</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;rightEyeDown&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.5719394</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.27742136</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;noseLeft&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.47886324</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.39542776</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;noseRight&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.52901316</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.3946445</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;mouthUp&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.50311553</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.44111547</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;mouthDown&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.5032443</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.4982476</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;leftPupil&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.4398567</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.26566792</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;rightPupil&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.57429</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.26926404</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;upperJawlineLeft&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.364641</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.25789997</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;midJawlineLeft&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.3910422</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.46887168</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;chinBottom&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.5044233</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.5957734</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;midJawlineRight&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.63242453</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.47487956</span><span style="color:#D4D4D4;">
                },
                {
                    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
                        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;upperJawlineRight&quot;</span><span style="color:#D4D4D4;">
                    },
                    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.6651306</span><span style="color:#D4D4D4;">,
                    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.2652495</span><span style="color:#D4D4D4;">
                }
            ],
            </span><span style="color:#9CDCFE;">&quot;MouthOpen&quot;</span><span style="color:#D4D4D4;">: {
                </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">95.07979</span><span style="color:#D4D4D4;">,
                </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#569CD6;">false</span><span style="color:#D4D4D4;">
            },
            </span><span style="color:#9CDCFE;">&quot;Mustache&quot;</span><span style="color:#D4D4D4;">: {
                </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">80.48857</span><span style="color:#D4D4D4;">,
                </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#569CD6;">false</span><span style="color:#D4D4D4;">
            },
            </span><span style="color:#9CDCFE;">&quot;Pose&quot;</span><span style="color:#D4D4D4;">: {
                </span><span style="color:#9CDCFE;">&quot;Pitch&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">-0.50104016</span><span style="color:#D4D4D4;">,
                </span><span style="color:#9CDCFE;">&quot;Roll&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">-0.11814453</span><span style="color:#D4D4D4;">,
                </span><span style="color:#9CDCFE;">&quot;Yaw&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">-0.8540245</span><span style="color:#D4D4D4;">
            },
            </span><span style="color:#9CDCFE;">&quot;Quality&quot;</span><span style="color:#D4D4D4;">: {
                </span><span style="color:#9CDCFE;">&quot;Brightness&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">32.687115</span><span style="color:#D4D4D4;">,
                </span><span style="color:#9CDCFE;">&quot;Sharpness&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">94.08263</span><span style="color:#D4D4D4;">
            },
            </span><span style="color:#9CDCFE;">&quot;Smile&quot;</span><span style="color:#D4D4D4;">: {
                </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">98.75468</span><span style="color:#D4D4D4;">,
                </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#569CD6;">false</span><span style="color:#D4D4D4;">
            },
            </span><span style="color:#9CDCFE;">&quot;Sunglasses&quot;</span><span style="color:#D4D4D4;">: {
                </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">98.83094</span><span style="color:#D4D4D4;">,
                </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#569CD6;">false</span><span style="color:#D4D4D4;">
            }
        }
    ],
    </span><span style="color:#9CDCFE;">&quot;OrientationCorrection&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#569CD6;">null</span><span style="color:#D4D4D4;">,
    </span><span style="color:#9CDCFE;">&quot;ResponseMetadata&quot;</span><span style="color:#D4D4D4;">: {
        </span><span style="color:#9CDCFE;">&quot;RequestId&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;1aec37d3-d585-4bc4-8d22-c045ced2f9cb&quot;</span><span style="color:#D4D4D4;">,
        </span><span style="color:#9CDCFE;">&quot;Metadata&quot;</span><span style="color:#D4D4D4;">: {}
    },
    </span><span style="color:#9CDCFE;">&quot;ContentLength&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">3345</span><span style="color:#D4D4D4;">,
    </span><span style="color:#9CDCFE;">&quot;HttpStatusCode&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">200</span><span style="color:#D4D4D4;">
}</pre></div>
</lj-spoiler>
The service returns you array of faces recognized and a lot of details for each of the faces. The details usually have confidence in perents (I filter everything bellow 90% level confidence) and some value. Values are often just boolean. For example the following element shows that Rekognition is pretty sure (98.75%) that a person on the image is not smiling (Value=false):
<div style="text-align: center;"><pre style="color:black; border:solid 1px darkgray; padding:10px; text-align:left;display: inline-block; background:#1e1e1e">
<span style="color:#9CDCFE;">&quot;Smile&quot;</span><span style="color:#D4D4D4;">: {
    </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">98.75468</span><span style="color:#D4D4D4;">,
    </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#569CD6;">false</span><span style="color:#D4D4D4;">
}</pre></div>
We get list of emotions as well. There can be several possible emotions and all of the are stored in the faceDetail.Emotions property. The same approach here, we have confidence and emotions value. In the following example the system is pretty sure that the person is CALM (confidence is high):
<div style="text-align: center;"><pre style="color:black; border:solid 1px darkgray; padding:10px; text-align:left;display: inline-block; background:#1e1e1e">
<span style="color:#D4D4D4;">{
    </span><span style="color:#9CDCFE;">&quot;Confidence&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">86.822525</span><span style="color:#D4D4D4;">,
    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;CALM&quot;</span><span style="color:#D4D4D4;">
    }
}</pre></div>
<p>Besides that we have really usefull list of face features with their positions, which are returned in the faceDetail.Landmarks list.</p>
<div style="text-align: center;"><pre style="color:black; border:solid 1px darkgray; padding:10px; text-align:left;display: inline-block; background:#1e1e1e">
<span style="color:#9CDCFE;">&quot;Landmarks&quot;</span><span style="color:#D4D4D4;">: [
{
    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;eyeLeft&quot;</span><span style="color:#D4D4D4;">
    },
    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.4398567</span><span style="color:#D4D4D4;">,
    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.26566792</span><span style="color:#D4D4D4;">
},
{
    </span><span style="color:#9CDCFE;">&quot;Type&quot;</span><span style="color:#D4D4D4;">: {
        </span><span style="color:#9CDCFE;">&quot;Value&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#CE9178;">&quot;eyeRight&quot;</span><span style="color:#D4D4D4;">
    },
    </span><span style="color:#9CDCFE;">&quot;X&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.57429</span><span style="color:#D4D4D4;">,
    </span><span style="color:#9CDCFE;">&quot;Y&quot;</span><span style="color:#D4D4D4;">: </span><span style="color:#B5CEA8;">0.26926404</span><span style="color:#D4D4D4;">
},</pre></div>
Please not that position of the landmars are in relative format and not absolute pixels. For example 'X=.5, Y=.5' value signifies that the feature is exactly in the middle of the picture. With WPF those coordinate transforms could be tricky and I suggest you to check how I use Canvas along with Image and methods GetImageCoordsForLandmark() and ImageToCanvasCoords() to position marks. If you run the program you will get all landmarks marked as small blue circles and putting mouse over any of those mark will give you a popup with the landmark name:
<center>
<img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_10891.jpg" alt="" title="">
</center>
<p>In my program I used positions of eyes and nose to place glasses and a clown nose on the picture in the right place and with the right scale. It comes out pretty good and works correctly even in complex cases when the head is tilted and rotated in 3D:</p>
<center>
<img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_11183.jpg" alt="" title=""><br><small style="color:gray;font-size:10pt">Used a photo by <a href="https://unsplash.com/@w_lissa071">Wadi Lissa</a> on Unsplash</small>
</center>
My experience shows that the Rekognition service is pretty good and easy to use so give it a try if you need such functionality. It is a lot of fun.]]></content:encoded></item><item><title>Lambda functions as a serverless backend, C# tutorial</title><link>https://konstantin.gladyou.click/posts/2020-04-29-lambda-functions-as-a-serverless-backend-c-tutorial/</link><pubDate>Wed, 29 Apr 2020 01:25:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2020-04-29-lambda-functions-as-a-serverless-backend-c-tutorial/</guid><description>&lt;font style="font-size:12pt;">
&lt;center>
&lt;img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_8125.jpg" alt="" title="">
&lt;br>&lt;small style="color:gray;font-size:10pt">Photo by &lt;a href="https://unsplash.com/@foxfox?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText">Natalia Y&lt;/a> on Unsplash&lt;/small>&lt;/center>
In the &lt;a href="https://konstantin.gladyou.click/posts/2020-04-28-serverless-deploying-angular-8-on-aws-s3-c-tutorial/">previous post&lt;/a> I showed how we can host an Angular site on AWS S3. In this post I am going to add server side to our application.</description><content:encoded><![CDATA[<font style="font-size:12pt;">
<center>
<img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_8125.jpg" alt="" title="">
<br><small style="color:gray;font-size:10pt">Photo by <a href="https://unsplash.com/@foxfox?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Natalia Y</a> on Unsplash</small></center>
In the <a href="https://konstantin.gladyou.click/posts/2020-04-28-serverless-deploying-angular-8-on-aws-s3-c-tutorial/">previous post</a> I showed how we can host an Angular site on AWS S3. In this post I am going to add server side to our application.
<p>Code for this tutorial is available in <a href="https://github.com/bukov-ka/articles_code/tree/lambdaBackend">GitHub</a>, so feel free to download it and check the two projects: WebConjugacion is an Angular client working with Lambda backend and LambdaConjugacion is the backend itself.</p>
<p>In our application the main service returns 10 random Spanish verb forms and we implemented that by using JSON file and simple Angular service. Here we are going to move it to C# implementation and use AWS to encapsulate this code in a form which can be consumed by the Angular application.</p>
<lj-spoiler title="Lambda business logic implementation">
<div style="text-align: center;"><pre style="color:black; border:solid 1px darkgray; padding:10px; text-align:left;display: inline-block; background:#1e1e1e">
<span style="color:#D4D4D4;">    </span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">class</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">Data</span><span style="color:#D4D4D4;">
    {
        </span><span style="color:#569CD6;">private</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">static</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">List</span><span style="color:#D4D4D4;">&lt;</span><span style="color:#4EC9B0;">WordViewModel</span><span style="color:#D4D4D4;">&gt; </span><span style="color:#9CDCFE;">Verbs</span><span style="color:#D4D4D4;"> { </span><span style="color:#569CD6;">get</span><span style="color:#D4D4D4;">; }
        </span><span style="color:#569CD6;">static</span><span style="color:#D4D4D4;"> </span><span style="color:#DCDCAA;">Data</span><span style="color:#D4D4D4;">()
        {
            </span><span style="color:#569CD6;">var</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">verbString</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">File</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">ReadAllText</span><span style="color:#D4D4D4;">(</span><span style="color:#CE9178;">&quot;verbsForLambda.json&quot;</span><span style="color:#D4D4D4;">);
            </span><span style="color:#9CDCFE;">Verbs</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">JsonConvert</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">DeserializeObject</span><span style="color:#D4D4D4;">&lt;</span><span style="color:#4EC9B0;">List</span><span style="color:#D4D4D4;">&lt;</span><span style="color:#4EC9B0;">WordViewModel</span><span style="color:#D4D4D4;">&gt;&gt;(</span><span style="color:#9CDCFE;">verbString</span><span style="color:#D4D4D4;">);
<pre><code>    }

    &lt;/span&gt;&lt;span style=&quot;color:#569CD6;&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color:#569CD6;&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color:#4EC9B0;&quot;&gt;List&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#4EC9B0;&quot;&gt;WordViewModel&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA;&quot;&gt;TenRandomVerbs&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#569CD6;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;tenseKeys&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;)
    {
        &lt;/span&gt;&lt;span style=&quot;color:#569CD6;&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;rnd&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color:#569CD6;&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color:#4EC9B0;&quot;&gt;Random&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;();
        &lt;/span&gt;&lt;span style=&quot;color:#569CD6;&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;allWordsModels&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;Data&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;Verbs&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;
            &lt;/span&gt;&lt;span style=&quot;color:#6A9955;&quot;&gt;// Filter for the selected tenses only&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;
            .&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA;&quot;&gt;Where&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;w&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;tenseKeys&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; == &lt;/span&gt;&lt;span style=&quot;color:#569CD6;&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; || &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;tenseKeys&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;Length&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; == &lt;/span&gt;&lt;span style=&quot;color:#B5CEA8;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; || &lt;/span&gt;&lt;span style=&quot;color:#6A9955;&quot;&gt;// Include all verbs if nothing is selected&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;
            &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;tenseKeys&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA;&quot;&gt;Contains&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;w&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;tense_key&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;))
            &lt;/span&gt;&lt;span style=&quot;color:#6A9955;&quot;&gt;// Shuffle&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;
            .&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA;&quot;&gt;OrderBy&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;o&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;rnd&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA;&quot;&gt;NextDouble&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;())
            .&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA;&quot;&gt;Take&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B5CEA8;&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;)
            .&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA;&quot;&gt;ToList&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;();
        &lt;/span&gt;&lt;span style=&quot;color:#569CD6;&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;words&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;allWordsModels&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;;
        &lt;/span&gt;&lt;span style=&quot;color:#C586C0;&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;words&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;;
    }
}
</code></pre>
<p></pre></div>
We read data from the same JSON file which was used in Angular, and we are doing it in the static constructor which will save us some time. Random 10 verb forms selection is straightforward and not optimal (we will optimize this code later). We just sort the data based on random values and select the first 10 items.
</lj-spoiler></p>
<p>Amazon provides a project template named &ldquo;AWS Lambda Project with Tests (.NET Core - C#)&rdquo; which is really easy to use. It contains a method FunctionHandler which we will update. We don&rsquo;t want our service to be stateless, so we will pass a string with tenses selected by user and we will return an object which contains 10 random items. Our method will consume the business logic we just created:</p>
<div style="text-align: center;"><pre style="color:black; border:solid 1px darkgray; padding:10px; text-align:left;display: inline-block; background:#1e1e1e">
<span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">object</span><span style="color:#D4D4D4;"> </span><span style="color:#DCDCAA;">FunctionHandler</span><span style="color:#D4D4D4;">(</span><span style="color:#569CD6;">string</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">filter</span><span style="color:#D4D4D4;">, </span><span style="color:#4EC9B0;">ILambdaContext</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">context</span><span style="color:#D4D4D4;">)
{
    </span><span style="color:#C586C0;">return</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">Data</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">TenRandomVerbs</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">string</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">IsNullOrEmpty</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">filter</span><span style="color:#D4D4D4;">) ? </span><span style="color:#569CD6;">null</span><span style="color:#D4D4D4;"> : </span><span style="color:#9CDCFE;">filter</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">Split</span><span style="color:#D4D4D4;">(</span><span style="color:#CE9178;">&quot;,&quot;</span><span style="color:#D4D4D4;">));
}</pre></div>
<p>Now we can publish this function as a new Lambda GetRandomVerbs, but in its current state it is not accessible as a web service. To convert it to an API we need to use API Gateway.</p>
<p>In API Gateway there are 2 options available: REST API and HTTP API. You can check differences between theme <a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-vs-rest.html">here</a>, but in short REST API is more flexible in configuration, but slower, and HTTP will give you more speed, but less options. I will show you both options starting with the classic REST API.</p>
<lj-spoiler title="REST API Gateway">
In the API Gateway we click on the Create API button and choose REST API->Build:
<a target="_blank" href="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_8313.png"><img style="display:block;margin-left:auto;margin-right:auto" src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_8313.png" alt="" title=""></a>
After the API is created we need to add a GET action. Actions -> Create Method, select GET from the dropdown and save. In the Setup we need to select integration type (Lambda Function), region, function name (autocomplete is available) and click Save.
<p><a target="_blank" href="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_8688.png"><img style="display:block;margin-left:auto;margin-right:auto" src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_8688.png" alt="" title=""></a>
We will get default pipeline, but since we need to pass a parameter, we need to slightly modify it. In the Method Request block we need to add a parameter &ldquo;input&rdquo; and I prefer to have it in query string:
<a target="_blank" href="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_8905.png"><img style="display:block;margin-left:auto;margin-right:auto" src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_8905.png" alt="" title=""></a></p>
<p>And in the Integration Request block we pass this parameter to our Lambda with Mapping Template option. In more complex cases we have JSON there, but since our parameter is a string the template is really simple:
<a target="_blank" href="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_9042.png"><img style="display:block;margin-left:auto;margin-right:auto" src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_9042.png" alt="" title=""></a></p>
<p>And now you can click Test, set input=gerund as a sample query string and get correct result:
<a target="_blank" href="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_9336.png"><img style="display:block;margin-left:auto;margin-right:auto" src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_9336.png" alt="" title=""></a></p>
<p>Now you can deploy this API, you will be asked to create a stage (I named my stage &ldquo;test&rdquo;) and you will have an URL to call your Lambda through any browser. The URL contains id of your API, region and stage name (<a href="https://hi5s52i4xb.execute-api.eu-west-2.amazonaws.com/test/?input=gerund)">https://hi5s52i4xb.execute-api.eu-west-2.amazonaws.com/test/?input=gerund)</a>. You can add query parameters and get results.</p>
<p>But if you try this call in the Angular code, you will get an error in the Dev Console and nothing more. Why? Because we host our Angular application on S3 and we make call to an API Gateway and those are two different domains and security policies won&rsquo;t allow us to simply make the call.</p>
<p>We need to use CORS headers (Cross-origin resource sharing). API Gateway allows to do this pretty easily. We need to go to our API and choose Action-&gt;Enable CORS. In the Access-Control-Allow-Origin we need to specify allowed domains, but by default there is &lsquo;*&rsquo; there which allows call from any domain. I will keep it this way.</p>
<p>And that&rsquo;s it! We can put this URL to our Angular client and see it working!
</lj-spoiler></p>
<lj-spoiler title="HTTP API Gateway">
Now when we know how to create a REST API, let's do similar work with HTTP API. This kind of integration gives more speed but uses low level approach. Our Lambda consumes APIGatewayProxyRequest object and creates APIGatewayProxyResponse:
<div style="text-align: center;"><pre style="color:black; border:solid 1px darkgray; padding:10px; text-align:left;display: inline-block; background:#1e1e1e">
<span style="color:#569CD6;">st</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">string</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">filterParameterKey</span><span style="color:#D4D4D4;"> = </span><span style="color:#CE9178;">&quot;input&quot;</span><span style="color:#D4D4D4;">;
</span><span style="color:#569CD6;">public</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">APIGatewayProxyResponse</span><span style="color:#D4D4D4;"> </span><span style="color:#DCDCAA;">Get</span><span style="color:#D4D4D4;">(
</span><span style="color:#4EC9B0;">APIGatewayProxyRequest</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">request</span><span style="color:#D4D4D4;">, </span><span style="color:#4EC9B0;">ILambdaContext</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">context</span><span style="color:#D4D4D4;">)
{
    </span><span style="color:#569CD6;">string</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">filter</span><span style="color:#D4D4D4;"> = </span><span style="color:#569CD6;">null</span><span style="color:#D4D4D4;">;
    </span><span style="color:#C586C0;">if</span><span style="color:#D4D4D4;"> (</span><span style="color:#9CDCFE;">request</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">QueryStringParameters</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">ContainsKey</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">filterParameterKey</span><span style="color:#D4D4D4;">))
    {
        </span><span style="color:#9CDCFE;">filter</span><span style="color:#D4D4D4;"> = </span><span style="color:#9CDCFE;">request</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">QueryStringParameters</span><span style="color:#D4D4D4;">[</span><span style="color:#9CDCFE;">filterParameterKey</span><span style="color:#D4D4D4;">];
<pre><code>}
&lt;/span&gt;&lt;span style=&quot;color:#569CD6;&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color:#569CD6;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA;&quot;&gt;GetTenVerbs&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;filter&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;);

&lt;/span&gt;&lt;span style=&quot;color:#C586C0;&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color:#DCDCAA;&quot;&gt;CreateResponse&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;);
</code></pre>
<p>}</p>
<p></span><span style="color:#4EC9B0;">APIGatewayProxyResponse</span><span style="color:#D4D4D4;"> </span><span style="color:#DCDCAA;">CreateResponse</span><span style="color:#D4D4D4;">(</span><span style="color:#4EC9B0;">List</span><span style="color:#D4D4D4;">&lt;</span><span style="color:#4EC9B0;">WordViewModel</span><span style="color:#D4D4D4;">&gt; </span><span style="color:#9CDCFE;">result</span><span style="color:#D4D4D4;">)
{
</span><span style="color:#569CD6;">int</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">statusCode</span><span style="color:#D4D4D4;"> = (</span><span style="color:#9CDCFE;">result</span><span style="color:#D4D4D4;"> != </span><span style="color:#569CD6;">null</span><span style="color:#D4D4D4;">) ?
(</span><span style="color:#569CD6;">int</span><span style="color:#D4D4D4;">)</span><span style="color:#9CDCFE;">HttpStatusCode</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">OK</span><span style="color:#D4D4D4;"> :
(</span><span style="color:#569CD6;">int</span><span style="color:#D4D4D4;">)</span><span style="color:#9CDCFE;">HttpStatusCode</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">InternalServerError</span><span style="color:#D4D4D4;">;</p>
<pre><code>&lt;/span&gt;&lt;span style=&quot;color:#569CD6;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; = (&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; != &lt;/span&gt;&lt;span style=&quot;color:#569CD6;&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;) ?
    &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;JsonConvert&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#DCDCAA;&quot;&gt;SerializeObject&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;) : &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;Empty&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;;

&lt;/span&gt;&lt;span style=&quot;color:#569CD6;&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color:#569CD6;&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color:#4EC9B0;&quot;&gt;APIGatewayProxyResponse&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;
{
    &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;StatusCode&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;statusCode&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;,
    &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;Body&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;,
    &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;Headers&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color:#569CD6;&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color:#4EC9B0;&quot;&gt;Dictionary&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#569CD6;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#569CD6;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;&amp;gt;
</code></pre>
<p>{
{ </span><span style="color:#CE9178;">&quot;Content-Type&quot;</span><span style="color:#D4D4D4;">, </span><span style="color:#CE9178;">&quot;application/json&quot;</span><span style="color:#D4D4D4;"> },
{ </span><span style="color:#CE9178;">&quot;Access-Control-Allow-Origin&quot;</span><span style="color:#D4D4D4;">, </span><span style="color:#CE9178;">&quot;*&quot;</span><span style="color:#D4D4D4;"> }
}
};</p>
<pre><code>&lt;/span&gt;&lt;span style=&quot;color:#C586C0;&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color:#9CDCFE;&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;color:#D4D4D4;&quot;&gt;;
</code></pre>
<p>}</pre></div>
Please note the Access-Control-Allow-Origin header. It is the CORS header which previously was created by Gateway API, but here we need to implement it explicitly.</p>
<p>After publishing this new Lambda, we need to create an HTTP API in the API Gateway which is pretty straightforward:
<a target="_blank" href="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_9646.png"><img style="display:block;margin-left:auto;margin-right:auto" src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_9646.png" alt="" title=""></a></p>
<p><a target="_blank" href="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_9845.png"><img style="display:block;margin-left:auto;margin-right:auto" src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_9845.png" alt="" title=""></a></p>
<p>But it won&rsquo;t work until you give execution rights explicitly:</p>
<pre>aws lambda add-permission --function-name arn:aws:lambda:eu-west-3:908478757030:function:GetRandomVerbs --source-arn arn:aws:execute-api:eu-west-3:908478757030:pt2vedqyte/* --principal apigateway.amazonaws.com --statement-id statement-id-guid --action lambda:InvokeFunction</pre>
<p>Now your gateway can call your Lambda. You can take the invocation url, add the route for your lambda, query parameters, and get result from browser:</p>
<pre>https://pt1vedqzte.execute-api.eu-west-3.amazonaws.com/test/GetRandomVerbs?input=gerund</pre>
<p>But to get things running, you need to configure CORS at the Gateway. I allowed everything filling the fields with &lsquo;*&rsquo;s:
<a target="_blank" href="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_10236.png"><img style="display:block;margin-left:auto;margin-right:auto" src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_10236.png" alt="" title=""></a>
And here you go. We have now both REST API and HTTP API for our application.
</lj-spoiler></p>
</font>]]></content:encoded></item><item><title>Serverless deploying Angular 8 on AWS S3, C# tutorial</title><link>https://konstantin.gladyou.click/posts/2020-04-28-serverless-deploying-angular-8-on-aws-s3-c-tutorial/</link><pubDate>Tue, 28 Apr 2020 04:06:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2020-04-28-serverless-deploying-angular-8-on-aws-s3-c-tutorial/</guid><description>&lt;font style="font-size:12pt;">
&lt;center>&lt;img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_6228.jpg" alt="" title="">&lt;br>&lt;small style="color:gray;font-size:10pt">Photo by &lt;a href="https://unsplash.com/@scottwebb?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText">Scott Webb&lt;/a> on Unsplash&lt;/small>&lt;/center>
Let's start the theme of serverless application on AWS from the very beginning. Say we have simple Angular application and we need to host it somewhere. AWS S3 can help us with that and it is a good start to serverless. So let's do it!</description><content:encoded><![CDATA[<font style="font-size:12pt;">
<center><img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_6228.jpg" alt="" title=""><br><small style="color:gray;font-size:10pt">Photo by <a href="https://unsplash.com/@scottwebb?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Scott Webb</a> on Unsplash</small></center>
Let's start the theme of serverless application on AWS from the very beginning. Say we have simple Angular application and we need to host it somewhere. AWS S3 can help us with that and it is a good start to serverless. So let's do it!
<p>Code for this article is available on <a href="https://github.com/bukov-ka/articles_code/tree/S3Deploy">GitHub</a>. Project WebConjugacion.csproj is an Angular8 application without backend code. It is a Spanish conjugation trainer which asks you to put a verb in some random form and checks you answer:
<img style="border:solid 1px darkgray; margin-left:auto; margin-right:auto; display:block" src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_6657.jpg" alt="" title="">
Services are implemented as .json-files in the assets folder. Angular client send get requests, but there is no any custom backend code envolved. Web-server just need to return the whole file:</p>
<div style="text-align: center;"><pre style="color:black; border:solid 1px darkgray; padding:10px; text-align:left;display: inline-block; background:#1e1e1e">
<span style="color:#DCDCAA;">getTenses</span><span style="color:#D4D4D4;">(): </span><span style="color:#4EC9B0;">Observable</span><span style="color:#D4D4D4;">&lt;</span><span style="color:#4EC9B0;">Mood</span><span style="color:#D4D4D4;">[]&gt; {
  </span><span style="color:#569CD6;">const</span><span style="color:#D4D4D4;"> </span><span style="color:#9CDCFE;">httpOptions</span><span style="color:#D4D4D4;"> = {
    </span><span style="color:#9CDCFE;">headers:</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">new</span><span style="color:#D4D4D4;"> </span><span style="color:#4EC9B0;">HttpHeaders</span><span style="color:#D4D4D4;">({
      </span><span style="color:#CE9178;">'Content-Type'</span><span style="color:#9CDCFE;">:</span><span style="color:#D4D4D4;"> </span><span style="color:#CE9178;">'application/json'</span><span style="color:#D4D4D4;">
    })
  };
<p></span><span style="color:#C586C0;">return</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">this</span><span style="color:#D4D4D4;">.</span><span style="color:#9CDCFE;">http</span><span style="color:#D4D4D4;">.</span><span style="color:#DCDCAA;">get</span><span style="color:#D4D4D4;">&lt;</span><span style="color:#4EC9B0;">Mood</span><span style="color:#D4D4D4;">[]&gt;(</span><span style="color:#CE9178;">&lsquo;filterTree.json&rsquo;</span><span style="color:#D4D4D4;">, </span><span style="color:#9CDCFE;">httpOptions</span><span style="color:#D4D4D4;">)
.</span><span style="color:#DCDCAA;">pipe</span><span style="color:#D4D4D4;">(
</span><span style="color:#DCDCAA;">catchError</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">err</span><span style="color:#D4D4D4;"> </span><span style="color:#569CD6;">=&gt;</span><span style="color:#D4D4D4;"> {
</span><span style="color:#C586C0;">return</span><span style="color:#D4D4D4;"> </span><span style="color:#DCDCAA;">throwError</span><span style="color:#D4D4D4;">(</span><span style="color:#9CDCFE;">err</span><span style="color:#D4D4D4;">);
}
)
);
}</pre></div></p>
<p>I have created an S3 bucket named kborisov-aws-test-artifacts and now we need to give public access to it. You can do that either during the bucket creation or after, in the settings. Tab Block Public Access has a bunch of checkboxes and I just reset all of them.
<a target="_blank" href="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_7486.png"><img style="margin-left:auto; margin-right:auto; display:block" src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_7486.png" alt="staticsiteproperties.png" title="staticsiteproperties.png"></a></p>
<p>Convertion of the bucket to a web server is done at the Properties tab. There is a &ldquo;Static website hosting&rdquo; item which is disabled by default. Enable it and click &ldquo;Save&rdquo; and that&rsquo;s it:
<a target="_blank" href="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_7252.png"><img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_7252.png" style="margin-left:auto; margin-right:auto; display:block" alt="staticsiteproperties.png" title="staticsiteproperties.png"></a></p>
<p>Policy at the Permissions -&gt; Bucket Policy is used to control access. I have everything accessible in my bucket:</p>
<div style="text-align: center;"><pre style="color:black; border:solid 1px darkgray; padding:10px; text-align:left;display: inline-block">
{
    "Version": "2012-10-17",
    "Id": "StaticWebsiteReadAllowed",
    "Statement": [
        {
            "Sid": "Stmt2586028788337",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<b>kborisov-aws-test-artifacts</b>/*"
        }
    ]
}</pre></div>
You can generate policy by the Policy Generator allowing everyone to do GetObject on your S3.
<p>For debug purposes it is good to allow listing objects in the bucket. In this case you will get usual 404 error if you try to access file which does not exist. Otherwise you will get 403 Access Denied which is not informative:
<a target="_blank" href="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_7930.png"><img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_7930.png" alt="" style="margin-left:auto; margin-right:auto; display:block" title=""></a></p>
<p>Ok at this point our bucket is prepared to serve as a web-server for our code, but our code is not quite ready yet. By default Angular code is expected to be placed in the root folder of the server and this is how Debug mode works. But I wanted to have my site in a subfolder. Let&rsquo;s configure our Angular app to be placed in the folder /aws-test/aws-publish/ClientApp/dist/.</p>
<p>It is done by setting base-href parameter. I modified package.json by adding build:Debug and build:Release scripts:</p>
<div style="text-align: center;"><pre style="color:black; border:solid 1px darkgray; padding:10px; text-align:left;display: inline-block; ">
 <span style="color:#2E75B6;">&quot;scripts&quot;</span>: {
    <span style="color:#2E75B6;">&quot;ng&quot;</span>: <span style="color:#A31515;">&quot;ng&quot;</span>,
    <span style="color:#2E75B6;">&quot;start&quot;</span>: <span style="color:#A31515;">&quot;ng serve&quot;</span>,
    <span style="color:#2E75B6;">&quot;build&quot;</span>: <span style="color:#A31515;">&quot;ng build&quot;</span>,
    <span style="color:#2E75B6;">&quot;build:Debug&quot;</span>: <span style="color:#A31515;">&quot;ng build --dev --base-href /&quot;</span>,
    <span style="color:#2E75B6;">&quot;build:Release&quot;</span>: <span style="color:#A31515;">&quot;ng build --prod --base-href=https://konstantin.gladyou.click/aws-test/aws-publish/ClientApp/dist/&quot;</span>,</pre></div>
<p>And now we need to modify the project file to use those scripts:</p>
<div style="text-align: center;"><pre style="color:black; border:solid 1px darkgray; padding:10px; text-align:left;display: inline-block;">
<span style="color:Blue;">&lt;</span><span style="color:#A31515;">Target</span><span style="color:Blue;"> </span><span style="color:Red;">Name</span><span style="color:Blue;">=</span>&quot;<span style="color:Blue;">PublishRunWebpack</span>&quot;<span style="color:Blue;"> </span><span style="color:Red;">AfterTargets</span><span style="color:Blue;">=</span>&quot;<span style="color:Blue;">ComputeFilesToPublish</span>&quot;<span style="color:Blue;">&gt;</span>
<span style="color:Blue;">    &lt;!--</span><span style="color:Green;"> As part of publishing, ensure the JS resources are freshly built in production mode </span><span style="color:Blue;">--&gt;</span>
<span style="color:Blue;">    &lt;</span><span style="color:#A31515;">Exec</span><span style="color:Blue;"> </span><span style="color:Red;">WorkingDirectory</span><span style="color:Blue;">=</span>&quot;<span style="color:Blue;">$(SpaRoot)</span>&quot;<span style="color:Blue;"> </span><span style="color:Red;">Command</span><span style="color:Blue;">=</span>&quot;<span style="color:Blue;">npm install</span>&quot;<span style="color:Blue;"> /&gt;</span>
<span style="color:Blue;">    &lt;</span><span style="color:#A31515;">Exec</span><span style="color:Blue;"> </span><span style="color:Red;">WorkingDirectory</span><span style="color:Blue;">=</span>&quot;<span style="color:Blue;">$(SpaRoot)</span>&quot;<span style="color:Blue;"> </span><span style="color:Red;">Command</span><span style="color:Blue;">=</span>&quot;<span style="color:Blue;">npm run build:$(Configuration) -- --prod</span>&quot;<span style="color:Blue;"> /&gt;</span>
<span style="color:Blue;">    &lt;</span><span style="color:#A31515;">Exec</span><span style="color:Blue;"> </span><span style="color:Red;">WorkingDirectory</span><span style="color:Blue;">=</span>&quot;<span style="color:Blue;">$(SpaRoot)</span>&quot;<span style="color:Blue;"> </span><span style="color:Red;">Command</span><span style="color:Blue;">=</span>&quot;<span style="color:Blue;">npm run build:ssr -- --prod</span>&quot;<span style="color:Blue;"> </span><span style="color:Red;">Condition</span><span style="color:Blue;">=</span>&quot;<span style="color:Blue;"> '$(BuildServerSideRenderer)' == 'true' </span>&quot;<span style="color:Blue;"> /&gt;</pre></div>
This part does the trick <pre style="display:inline">&quot;<span style="color:Blue;">npm run build:$(Configuration) -- --prod</span>&quot;</pre>. Now we can publish our solution in an aws-publish, leave only the "dist" folder since we don't need anything besides the Angular app itself and upload it to the S3. And our site is available at the address https://<bucket_name>.s3.<region>.amazonaws.com/aws-test/aws-publish/ClientApp/dist/index.html
And it's a good start to move forward with serverless deploy. 
</font>]]></content:encoded></item><item><title>LINQ and Algorithmic Tasks</title><link>https://konstantin.gladyou.click/posts/2019-09-12-linq-and-algorithmic-tasks/</link><pubDate>Thu, 12 Sep 2019 15:51:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2019-09-12-linq-and-algorithmic-tasks/</guid><description>&lt;p style="text-align:center">&lt;img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_4566.png" alt="" title="">&lt;br>
&lt;font color="gray">Photo by &lt;a href="https://unsplash.com/@jjying?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText">JJ Ying&lt;/a> on &lt;a href="https://unsplash.com/search/photos/complicated?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText">Unsplash&lt;/a>&lt;/font>
&lt;/p>
&lt;p>A while ago I have found a very interesting blog of a Google interviewer &lt;a href="https://medium.com/@alexgolec">&lt;ins>Alex Golec&lt;/ins>&lt;/a>. He has several articles about interview questions with solutions in Python. And I solved the same problems in my favorite C# (without peeping at the answers of course!). And during checking my solution against the provided Python solutions I realized how much LINQ my way of thinking and my way of solving programming tasks.&lt;/p></description><content:encoded><![CDATA[<p style="text-align:center"><img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_4566.png" alt="" title=""><br>
<font color="gray">Photo by <a href="https://unsplash.com/@jjying?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">JJ Ying</a> on <a href="https://unsplash.com/search/photos/complicated?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></font>
</p>
<p>A while ago I have found a very interesting blog of a Google interviewer <a href="https://medium.com/@alexgolec"><ins>Alex Golec</ins></a>. He has several articles about interview questions with solutions in Python. And I solved the same problems in my favorite C# (without peeping at the answers of course!). And during checking my solution against the provided Python solutions I realized how much LINQ my way of thinking and my way of solving programming tasks.</p>
<p>Let me show what I mean. Here is the first task, <a href="https://medium.com/@alexgolec/google-interview-problems-ratio-finder-d7aa8bf201e3">Ratio Finder</a>:<blockquote>You have a set of known conversion rates such as:<br>— 1 hand equals 4 inches<br>— 4 inches equals 0.33333 feet<br>— 0.33333 feet equals 6.3125e-5 miles<br>— 6.3125e-5 miles equals 1.0737e-17 light years<br>Given such a list design an algorithm that takes two arbitrary unit values and returns the conversion rate between them.</blockquote>
And here is my solution for the task:<br/>
<a href="https://dotnetfiddle.net/Widget/3PY3mr">Fiddle</a>
<lj-spoiler title="Source"></p>
<pre style="color:black">
<span style="color:Blue;">static</span> (<span style="color:Blue;">string</span> source, <span style="color:Blue;">string</span> destination, <span style="color:Blue;">double</span> coef)[] coeffs = {
            (<span style="color:#A31515;">"foot"</span>, <span style="color:#A31515;">"inch"</span>, 12),
            (<span style="color:#A31515;">"hand"</span>, <span style="color:#A31515;">"inch"</span>, 4),
            (<span style="color:#A31515;">"mile"</span>, <span style="color:#A31515;">"foot"</span>, 5280),
            (<span style="color:#A31515;">"light year"</span>, <span style="color:#A31515;">"km"</span>, 9.461e+12),
            (<span style="color:#A31515;">"km"</span>, <span style="color:#A31515;">"mile"</span>, 0.621371)
        };
        <span style="color:Blue;">static</span> <span style="color:Blue;">void</span> Main(<span style="color:Blue;">string</span>[] args)
        {
            <span style="color:Blue;">var</span> allCoeffs = Queryable.Union<(<span style="color:Blue;">string</span> source, <span style="color:Blue;">string</span> destination, <span style="color:Blue;">double</span> coef)>(coeffs.AsQueryable(), coeffs.Select(s => (s.destination, s.source, 1 / s.coef))).ToArray();


            <span style="color:Blue;">var</span> unit1 = <span style="color:#A31515;">"hand"</span>;
            <span style="color:Blue;">var</span> unit2 = <span style="color:#A31515;">"light year"</span>;
            <span style="color:Blue;">var</span> result = SearchConversion(allCoeffs, unit1, unit2);

            Console.WriteLine(result);
        }

        <span style="color:Blue;">private</span> <span style="color:Blue;">static</span> <span style="color:Blue;">double</span> SearchConversion((<span style="color:Blue;">string</span> source, <span style="color:Blue;">string</span> destination, <span style="color:Blue;">double</span> coef)[] allCoeffs, <span style="color:Blue;">string</span> unit1, <span style="color:Blue;">string</span> unit2)
        {
            <span style="color:Blue;">var</span> result = 0.0;
            <span style="color:Blue;">var</span> conversionAdded = allCoeffs.Where(w => w.source == unit1).Select(s => (destination:s.destination, coef:s.coef)).ToDictionary(k => k.destination, e => e.coef);
            <span style="color:Blue;">bool</span> somethingChanged = <span style="color:Blue;">true</span>;
            <span style="color:Blue;">while</span> (somethingChanged)
            {
                somethingChanged = <span style="color:Blue;">false</span>;
                <span style="color:Blue;">foreach</span> (var existingConversion <span style="color:Blue;">in</span> conversionAdded.Keys.ToArray())
                {
                    <span style="color:Blue;">var</span> nextStep = allCoeffs.Where(w => w.source == existingConversion && !conversionAdded.ContainsKey(w.destination));
                    <span style="color:Blue;">foreach</span> (var newConversion <span style="color:Blue;">in</span> nextStep)
                    {
                        <span style="color:Blue;">if</span> (existingConversion == unit1) <span style="color:Blue;">continue</span>;
                        <span style="color:Blue;">var</span> newCoeff = conversionAdded[existingConversion] * newConversion.coef;
                        conversionAdded.Add(newConversion.destination, newCoeff);
                        somethingChanged = <span style="color:Blue;">true</span>;
                        <span style="color:Blue;">if</span> (newConversion.destination == unit2)
                        {
                            result = newCoeff;
                            <span style="color:Blue;">return</span> result;
                        }
                    }
                }
            }
            <span style="color:Blue;">return</span> result;
        }</pre>
</lj-spoiler>
<br/>
The first thing to mention is that LINQ statements can provide simple one-liners for solution steps. Without LINQ this would require separate methods or blocks of code. For example, here is the addition of reverse conversion to the conversions list:
<pre style="color:black">
<span style="color:Blue;">var</span> allCoeffs = Queryable.Union<(<span style="color:Blue;">string</span> source, <span style="color:Blue;">string</span> destination, <span style="color:Blue;">double</span> coef)>(
                coeffs.AsQueryable(), 
                coeffs.Select(s => (s.destination, s.source, 1 / s.coef)))
                .ToArray();</pre>
<p>The next good thing is that with LINQ you use iterative approach instead of recursion. With this code I am getting the next portion of conversions (breadth first search):</p>
<pre style="color:black">
<span style="color:Blue;">var</span> nextStep = allCoeffs.Where(w => w.source == existingConversion && !conversionAdded.ContainsKey(w.destination));</pre>
<p>The third thing which is not easy to show but really easy to notice, that LINQ allows you to manipulate your logic for debugging and refactoring. You could split a long expression into several parts. You could use .ToArray() to see results of computations. You cold make data transformation to improve performance (like converting Array to Dictionaly). Or you could even rewrite some portions of LINQ without LINQ to produce more clear and manageable code.</p>
<p>By the way, I am really pleased with the named tuples we have now in C#. It really makes code easier to read and implement.</p>
<p>And let&rsquo;s check the next interview task, <a href="https://medium.com/hackernoon/google-interview-questions-deconstructed-the-knights-dialer-f780d516f029">Knight Dialer</a>:</p>
<blockquote>
You place a knight chess piece on a phone dial pad. 
<pre style="color:black">
<span style="color:Blue;">1 2 3
4 5 6
7 8 9
 0</pre>
<p>This chess piece moves in an uppercase “L” shape: two steps horizontally followed by one vertically, or one step horizontally then two vertically.</p>
<p>Suppose you dial keys on the keypad using only hops a knight can make. Every time the knight lands on a key, we dial that key and make another hop. The starting position counts as being dialed.
How many distinct numbers can you dial in N hops from a particular starting position?</p>
</blockquote>
A really hard task taking into account performance challenges, but the solution looks simple:<br/>
<a href="https://dotnetfiddle.net/DpEZ1N">Fiddle</a>
<lj-spoiler title="Source">
<pre style="color:black">
<span style="color:Blue;">static</span> (<span style="color:Blue;">char</span> source, <span style="color:Blue;">char</span> destination)[] moves = {
            (<span style="color:#A31515;">'1'</span>,<span style="color:#A31515;">'6'</span>),
            (<span style="color:#A31515;">'1'</span>,<span style="color:#A31515;">'8'</span>),
            (<span style="color:#A31515;">'2'</span>,<span style="color:#A31515;">'7'</span>),
            (<span style="color:#A31515;">'2'</span>,<span style="color:#A31515;">'9'</span>),
            (<span style="color:#A31515;">'3'</span>,<span style="color:#A31515;">'4'</span>),
            (<span style="color:#A31515;">'3'</span>,<span style="color:#A31515;">'8'</span>),
            (<span style="color:#A31515;">'4'</span>,<span style="color:#A31515;">'3'</span>),
            (<span style="color:#A31515;">'4'</span>,<span style="color:#A31515;">'9'</span>),
            (<span style="color:#A31515;">'4'</span>,<span style="color:#A31515;">'0'</span>),
            (<span style="color:#A31515;">'6'</span>,<span style="color:#A31515;">'1'</span>),
            (<span style="color:#A31515;">'6'</span>,<span style="color:#A31515;">'0'</span>),
            (<span style="color:#A31515;">'6'</span>,<span style="color:#A31515;">'7'</span>),
            (<span style="color:#A31515;">'7'</span>,<span style="color:#A31515;">'6'</span>),
            (<span style="color:#A31515;">'7'</span>,<span style="color:#A31515;">'2'</span>),
            (<span style="color:#A31515;">'8'</span>,<span style="color:#A31515;">'1'</span>),
            (<span style="color:#A31515;">'8'</span>,<span style="color:#A31515;">'3'</span>),
            (<span style="color:#A31515;">'9'</span>,<span style="color:#A31515;">'4'</span>),
            (<span style="color:#A31515;">'9'</span>,<span style="color:#A31515;">'2'</span>),
            (<span style="color:#A31515;">'0'</span>,<span style="color:#A31515;">'4'</span>),
            (<span style="color:#A31515;">'0'</span>,<span style="color:#A31515;">'6'</span>)
        };
<pre><code>    &lt;span style=&quot;color:Blue;&quot;&gt;static&lt;/span&gt; &lt;span style=&quot;color:Blue;&quot;&gt;void&lt;/span&gt; Main(&lt;span style=&quot;color:Blue;&quot;&gt;string&lt;/span&gt;[] args)
    {
        &lt;span style=&quot;color:Blue;&quot;&gt;var&lt;/span&gt; unsymmetrical = moves.Where(w =&gt; !moves.Where(wi =&gt; wi.destination == w.source &amp;&amp; wi.source == w.destination).Any());
        &lt;span style=&quot;color:Blue;&quot;&gt;if&lt;/span&gt; (unsymmetrical.Any())
        {
            Console.WriteLine(&lt;span style=&quot;color:#A31515;&quot;&gt;&quot;Incorrect input&quot;&lt;/span&gt;);
        }
        &lt;span style=&quot;color:Blue;&quot;&gt;int&lt;/span&gt; N = 30;
        &lt;span style=&quot;color:Blue;&quot;&gt;char&lt;/span&gt; original = &lt;span style=&quot;color:#A31515;&quot;&gt;'0'&lt;/span&gt;;
        &lt;span style=&quot;color:Blue;&quot;&gt;var&lt;/span&gt; variantsCounts = &lt;span style=&quot;color:Blue;&quot;&gt;new&lt;/span&gt; List&lt;(&lt;span style=&quot;color:Blue;&quot;&gt;char&lt;/span&gt; digit, &lt;span style=&quot;color:Blue;&quot;&gt;long&lt;/span&gt; count)&gt;();
        variantsCounts.Add((original, 1));
        &lt;span style=&quot;color:Blue;&quot;&gt;for&lt;/span&gt; (&lt;span style=&quot;color:Blue;&quot;&gt;int&lt;/span&gt; i = 0; i &lt; N; i++)
        {
            &lt;span style=&quot;color:Blue;&quot;&gt;var&lt;/span&gt; nextRoundUngrouped = variantsCounts
                   .Join(moves, phone =&gt; phone.digit, move =&gt; move.source, (phone, move) =&gt; (digit: move.destination, count: phone.count)).ToArray();
            &lt;span style=&quot;color:Blue;&quot;&gt;var&lt;/span&gt; nextRoundGrouped = nextRoundUngrouped.GroupBy(g =&gt; g.digit).Select(s =&gt; (digit: s.Key, count: s.Sum(v=&gt;v.count))).ToList();
            variantsCounts = nextRoundGrouped;
        }
        &lt;span style=&quot;color:Blue;&quot;&gt;var&lt;/span&gt; sum = variantsCounts.Sum(s =&gt; s.count);
        Console.WriteLine(&lt;span style=&quot;color:#A31515;&quot;&gt;$&quot;Number of phones: &lt;/span&gt;{sum}&lt;span style=&quot;color:#A31515;&quot;&gt;&quot;&lt;/span&gt;);
    }&lt;/pre&gt;
</code></pre>
</lj-spoiler>
<p>And here you can see the same features: easy to read and easy to debug code and iterative approach. I split one LINQ expression which produces the next step data into two:<pre style="color:black">
                <span style="color:Blue;">var</span> nextRoundUngrouped = variantsCounts
                       .Join(moves, phone => phone.digit, move => move.source, (phone, move) => (digit: move.destination, count: phone.count)).ToArray();
                <span style="color:Blue;">var</span> nextRoundGrouped = nextRoundUngrouped.GroupBy(g => g.digit).Select(s => (digit: s.Key, count: s.Sum(v=>v.count))).ToList();</pre>
<p><br/>This allowed me in debug time to look into the data I have at each step. But it is really easy to put everything back together to get a little bit more of performance:<pre style="color:black">
<span style="color:Blue;">var</span> nextRoundGrouped = variantsCounts
.Join(moves, phone =&gt; phone.digit, move =&gt; move.source, (phone, move) =&gt; (digit: move.destination, count: phone.count))
.GroupBy(g =&gt; g.digit)
.Select(s =&gt; (digit: s.Key, count: s.Sum(v=&gt;v.count)))
.ToList();</pre></p>
</p>
<p>So now it is obvious for me that despite LINQ was introduced mostly to make business logic implementation easier for Enterprise application, it forms a new way of thinking in implementing algorithms. In many cases it allows to produce better code. And of course it is a lot of fun in using simple joins instead of nested loops.</p>]]></content:encoded></item><item><title>CSS tricks: A click counter without Javascript</title><link>https://konstantin.gladyou.click/posts/2019-03-17-css-tricks-a-click-counter-without-javascript/</link><pubDate>Sun, 17 Mar 2019 15:32:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2019-03-17-css-tricks-a-click-counter-without-javascript/</guid><description>Is it possible to make a click counter on a pure HTML/CSS without any Javascript involved? This came as an 'out of curiosity questions' from a friend web-developer. After short investigation I found out this technique which is not only funny, but which might be useful.
And here is the solution: JSFiddle. Click at the number in the Result window and see the numbers go from 1 to 4 in a cycle.</description><content:encoded><![CDATA[<figure class="aentry-post__figure aentry-post__figure--text-width" data-figure-type="image" data-image-type="standart">
<div class="aentry-post__img--text-width">
<img style="max-width: 100%" src="https://process.filestackapi.com/cache=expiry:max/resize=width:1050/compress/a4zCCHDRBaUSKdMPzMQA" />
<figcaption></figcaption>
</div>
</figure>
<p>Is it possible to make a click counter on a pure HTML/CSS without any Javascript involved? This came as an 'out of curiosity questions' from a friend web-developer. After short investigation I found out this technique which is not only funny, but which might be useful.</p>
<p>And here is the solution: <a href="http://jsfiddle.net/kborisov/tg4z9dfa">JSFiddle</a>. Click at the number in the Result window and see the numbers go from 1 to 4 in a cycle. With HTML and CSS only!</p>
<p>The idea is pretty simple: in the HTML we have only two checkboxes with labels to code 4 different states in binary format. And in the CSS we have 4 blocks generated with the :after pseudo-element. Only one of each gets visible based on the checkbox states.</p>
<p>Where this could be used? In the most cases Javascript is better than CSS in producing such effects. But CSS is better when we are talking not about behavior, but about presentation of data.</p>
<p>Say you have a test for users: a list of questions with checkbox or radiobuttons for answers. On a laptop it is better for to have separate checkboxes for answers, but on a mobile device checkboxes are too hard to use. It is better to have a large button for choosing answers on mobile. And the approach above allows you to implement this with the same HTML.</p>
<p>Besides that having representation logic in CSS instead of Javascipt makes this logic much easier to understand and maintain.</p>
]]></content:encoded></item><item><title>MS SQL Server for logical conclusion</title><link>https://konstantin.gladyou.click/posts/2019-03-17-ms-sql-server-for-logical-conclusion/</link><pubDate>Sun, 17 Mar 2019 15:05:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2019-03-17-ms-sql-server-for-logical-conclusion/</guid><description>&lt;center>&lt;img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_3903.jpg" alt="" title="">&lt;/center>
&lt;p>Did you know that MS SQL Server optimization techniques are so good that you can even use it to walk through millions and billions and trillions of possible solutions to find the correct one?&lt;/p></description><content:encoded><![CDATA[<center><img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_3903.jpg" alt="" title=""></center>
<p>Did you know that MS SQL Server optimization techniques are so good that you can even use it to walk through millions and billions and trillions of possible solutions to find the correct one?</p>
<p>Let me show how this works on a very simple (for a computer) sample. It is one of those mind blowing self-referring tests which can be found on the <a href="https://www.brainbashers.com/showpuzzles.asp?puzzle=ZYOT">BrainBashers</a> site:</p>
<code>1. The first question with B as the correct answer is: 
A.1  B.4  C.3  D.2 
<ol start="2">
<li>
<p>The answer to Question 4 is:
A.D  B.A  C.B  D.C</p>
</li>
<li>
<p>The answer to Question 1 is:
A.D  B.C  C.B  D.A</p>
</li>
<li>
<p>The number of questions which have D as the correct answer is:
A.3  B.2  C.1  D.0</p>
</li>
<li>
<p>The number of questions which have B as the correct answer is:
A.0  B.2  C.3  D.1 </code></p>
</li>
</ol>
<p>We will use Common Table Expressions for the query, which is a really great tool for complex queries. We do not even need real tables to work with, we will create all the data needed in the select query itself.</p>
<p>For a start let's get all the possible solutions for this puzzle. Here is the query:</p>
<pre style="color:black">
<span style="color:Blue;">with</span> t <span style="color:Blue;">as</span>
<span style="color:Gray;">(</span><span style="color:Blue;">select</span> <span style="color:Red;">'A'</span> <span style="color:Blue;">as</span> a
<span style="color:Blue;">union</span>
<span style="color:Blue;">select</span> <span style="color:Red;">'B'</span>
<span style="color:Blue;">union</span>
<span style="color:Blue;">select</span> <span style="color:Red;">'C'</span>
<span style="color:Blue;">union</span>
<span style="color:Blue;">select</span> <span style="color:Red;">'D'</span><span style="color:Gray;">)</span>
<span style="color:Blue;">select</span>  <span style="color:Gray;">*</span>
  <span style="color:Blue;">from</span> t <span style="color:Blue;">as</span> t1<span style="color:Gray;">,</span> t <span style="color:Blue;">as</span> t2<span style="color:Gray;">,</span> t <span style="color:Blue;">as</span> t3<span style="color:Gray;">,</span> t <span style="color:Blue;">as</span> t4<span style="color:Gray;">,</span> t <span style="color:Blue;">as</span> t5 <span style="color:Green;">/* Cross join */
</pre>
<p>Here we create list of the letters 'A', 'B', 'C' and 'D' which is possible answers for a single questions and join those letters with themselves five times to get all possible combinations:<br></p>
<center>
<img src="https://konstantin.gladyou.click/konstantin/bukov_net_30458650_4235.jpg" style="width:250px">
</center>
<p>This is good, but not good enough since we need only the right answer, not all of them. So let's add filter expressions in the WHERE clause.</p>
<p>And we have basically filter expressions, one for each questions of the puzzle. Let's take the first question and translate it to SQL.</p>
<code>1. The first question with B as the correct answer is: 
A.1  B.4  C.3  D.2 
</code>
<p>In SQL it will be very simple. We need to check all possible answers to the first question and ensure that the 'B' answer does not come before the given option:</p>
<pre style="color:black">
<span style="color:Blue;">   </span><span style="color:Gray;">(</span>t1<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'A'</span> <span style="color:Gray;">and</span> t1<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'B'</span><span style="color:Gray;">)</span>
<span style="color:Green;">--or (t1.a='B' and t4.a='B' --false)</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t1<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'C'</span> <span style="color:Gray;">and</span> t3<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'B'</span> <span style="color:Gray;">and</span> t1<span style="color:Gray;">.</span>a<span style="color:Gray;">!=</span><span style="color:Red;">'B'</span> <span style="color:Gray;">and</span> t2<span style="color:Gray;">.</span>a<span style="color:Gray;">!=</span><span style="color:Red;">'B'</span><span style="color:Gray;">)</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t1<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'D'</span> <span style="color:Gray;">and</span> t2<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'B'</span> <span style="color:Gray;">and</span> t1<span style="color:Gray;">.</span>a<span style="color:Gray;">!=</span><span style="color:Red;">'B'</span> <span style="color:Gray;">)</pre>
<p>The two first options are obviously false but let's keep them anyway. SQL Server should figure that by itself. The second questions is even more straightforward. We need to bind the 2nd and the 4th questions:</p><pre style="color:black">
<span style="color:Blue;">   </span><span style="color:Gray;">(</span>t2<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'A'</span> <span style="color:Gray;">and</span> t4<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'D'</span><span style="color:Gray;">)</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t2<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'B'</span> <span style="color:Gray;">and</span> t4<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'A'</span><span style="color:Gray;">)</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t2<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'C'</span> <span style="color:Gray;">and</span> t4<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'B'</span><span style="color:Gray;">)</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t2<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'D'</span> <span style="color:Gray;">and</span> t4<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'C'</span><span style="color:Gray;">)</pre><p>You get the idea. Let me show the final SQL for this puzzle:</p><lj-spoiler title="SQL query">
<pre style="color:black">
<span style="color:Blue;">with</span> t <span style="color:Blue;">as</span>
<span style="color:Gray;">(</span><span style="color:Blue;">select</span> <span style="color:Red;">'A'</span> <span style="color:Blue;">as</span> a
<span style="color:Blue;">union</span>
<span style="color:Blue;">select</span> <span style="color:Red;">'B'</span>
<span style="color:Blue;">union</span>
<span style="color:Blue;">select</span> <span style="color:Red;">'C'</span>
<span style="color:Blue;">union</span>
<span style="color:Blue;">select</span> <span style="color:Red;">'D'</span><span style="color:Gray;">)</span>
<span style="color:Blue;">select</span>  <span style="color:Gray;">*</span>
  <span style="color:Blue;">from</span> t <span style="color:Blue;">as</span> t1<span style="color:Gray;">,</span> t <span style="color:Blue;">as</span> t2<span style="color:Gray;">,</span> t <span style="color:Blue;">as</span> t3<span style="color:Gray;">,</span> t <span style="color:Blue;">as</span> t4<span style="color:Gray;">,</span> t <span style="color:Blue;">as</span> t5 <span style="color:Green;">/* Cross join */</span>
<span style="color:Blue;">where</span>
<span style="color:Gray;">(</span> <span style="color:Green;">-- 1</span>
<span style="color:Blue;">   </span><span style="color:Gray;">(</span>t1<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'A'</span> <span style="color:Gray;">and</span> t1<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'B'</span><span style="color:Gray;">)</span>
<span style="color:Green;">--or (t1.a='B' and t4.a='B' --false)</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t1<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'C'</span> <span style="color:Gray;">and</span> t3<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'B'</span> <span style="color:Gray;">and</span> t1<span style="color:Gray;">.</span>a<span style="color:Gray;">!=</span><span style="color:Red;">'B'</span> <span style="color:Gray;">and</span> t2<span style="color:Gray;">.</span>a<span style="color:Gray;">!=</span><span style="color:Red;">'B'</span><span style="color:Gray;">)</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t1<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'D'</span> <span style="color:Gray;">and</span> t2<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'B'</span> <span style="color:Gray;">and</span> t1<span style="color:Gray;">.</span>a<span style="color:Gray;">!=</span><span style="color:Red;">'B'</span> <span style="color:Gray;">)</span>
<span style="color:Gray;">)</span>
<span style="color:Gray;">and</span>
<span style="color:Gray;">(</span> <span style="color:Green;">-- 2</span>
<span style="color:Blue;">   </span><span style="color:Gray;">(</span>t2<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'A'</span> <span style="color:Gray;">and</span> t4<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'D'</span><span style="color:Gray;">)</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t2<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'B'</span> <span style="color:Gray;">and</span> t4<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'A'</span><span style="color:Gray;">)</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t2<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'C'</span> <span style="color:Gray;">and</span> t4<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'B'</span><span style="color:Gray;">)</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t2<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'D'</span> <span style="color:Gray;">and</span> t4<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'C'</span><span style="color:Gray;">)</span>
<span style="color:Gray;">)</span>
<span style="color:Gray;">and</span>
<span style="color:Gray;">(</span> <span style="color:Green;">-- 3</span>
<span style="color:Blue;">   </span><span style="color:Gray;">(</span>t3<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'A'</span> <span style="color:Gray;">and</span> t1<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'D'</span><span style="color:Gray;">)</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t3<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'B'</span> <span style="color:Gray;">and</span> t1<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'C'</span><span style="color:Gray;">)</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t3<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'C'</span> <span style="color:Gray;">and</span> t1<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'B'</span><span style="color:Gray;">)</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t3<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'D'</span> <span style="color:Gray;">and</span> t1<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'A'</span><span style="color:Gray;">)</span>
<span style="color:Gray;">)</span>
<span style="color:Gray;">and</span>
<span style="color:Gray;">(</span> <span style="color:Green;">-- 4</span>
<span style="color:Blue;">   </span><span style="color:Gray;">(</span>t4<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'A'</span> <span style="color:Gray;">and</span>	3<span style="color:Gray;">=(</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t1<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t2<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t3<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t4<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t5<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span><span style="color:Gray;">))</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t4<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'B'</span> <span style="color:Gray;">and</span> 2<span style="color:Gray;">=(</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t1<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t2<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t3<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t4<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t5<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span><span style="color:Gray;">))</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t4<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'C'</span> <span style="color:Gray;">and</span> 1<span style="color:Gray;">=(</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t1<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t2<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t3<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t4<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t5<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span><span style="color:Gray;">))</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t4<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'D'</span> <span style="color:Gray;">and</span> 0<span style="color:Gray;">=(</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t1<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t2<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t3<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t4<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t5<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'D'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span><span style="color:Gray;">))</span>
<span style="color:Gray;">)</span>
<span style="color:Gray;">and</span>
<span style="color:Gray;">(</span> <span style="color:Green;">-- 5</span>
<span style="color:Gray;">(</span>t5<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'A'</span> <span style="color:Gray;">and</span>	0<span style="color:Gray;">=(</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t1<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t2<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t3<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t4<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t5<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span><span style="color:Gray;">))</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t5<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'B'</span> <span style="color:Gray;">and</span> 2<span style="color:Gray;">=(</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t1<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t2<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t3<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t4<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t5<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span><span style="color:Gray;">))</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t5<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'C'</span> <span style="color:Gray;">and</span> 3<span style="color:Gray;">=(</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t1<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t2<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t3<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t4<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t5<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span><span style="color:Gray;">))</span>
<span style="color:Gray;">or</span><span style="color:Blue;"> </span><span style="color:Gray;">(</span>t5<span style="color:Gray;">.</span>a<span style="color:Gray;">=</span><span style="color:Red;">'D'</span> <span style="color:Gray;">and</span> 1<span style="color:Gray;">=(</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t1<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t2<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t3<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t4<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span>
					<span style="color:Gray;">+</span><span style="color:Blue;">case</span> <span style="color:Blue;">when</span> t5<span style="color:Gray;">.</span>a <span style="color:Gray;">=</span> <span style="color:Red;">'B'</span> <span style="color:Blue;">then</span> 1 <span style="color:Blue;">else</span> 0 <span style="color:Blue;">end</span><span style="color:Gray;">))</span>
<span style="color:Gray;">)</pre>
</lj-spoiler>
<br/>
<p>And running this query gives us the answer in no time: 'C D B C B'. But it is only 1024 variants. Let's try something harder!</p>
<p>How about the <a href="http://faculty.uml.edu/jpropp/srat-Q.txt">SELF-REFERENTIAL APTITUDE TEST</a>, by James Propp? The are <strong>5^19</strong> = <strong>1.90734863 × 10^13</strong> variants which is a pretty huge number even for modern computers. But MS SQL Server gives a solution ('DADBEDDEDABADBADBABE') in less than a second.</p>
<p>The querry is 20kB long but really easy to construct since it is the same questions in the form of SQL:</p>
<lj-spoiler title="20kb of SQL">
<pre>
with t as
(select 1 as a
union
select 2
union
select 3
union
select 4
union
select 5)
select  *
  from t as t1, t as t2, t as t3, t as t4, t as t5,
                    t as t6, t as t7, t as t8, t as t9, t as t10,
                    t as t11, t as t12, t as t13, t as t14, t as t15,
                    t as t16, t as t17, t as t18, t as t19, (select 5 as a) as t20 /* Cross join */
where 
(
(t1.a = 2 and t2.a = 2)
or (t1.a = 3 and t3.a = 2)
or (t1.a = 4 and t4.a = 2)
or (t1.a = 5 and t5.a = 2)
) /* 1 */
and
(
(t2.a = 1 and (t6.a = t7.a)
and (t1.a != t2.a) and (t2.a != t3.a) and (t4.a != t5.a) and (t5.a != t6.a)
/*and (t6.a != t7.a)*/ and (t7.a != t8.a) and (t8.a != t9.a) and (t9.a != t10.a)
and (t10.a != t11.a) and (t11.a != t12.a) and (t12.a != t13.a) and (t13.a != t14.a)
and (t14.a != t15.a) and (t15.a != t16.a) and (t16.a != t17.a) and (t17.a != t18.a) 
 and (t18.a != t19.a) and (t19.a != t20.a))
 or (t2.a = 2 and (t7.a = t8.a)
and (t1.a != t2.a) and (t2.a != t3.a) and (t4.a != t5.a) and (t5.a != t6.a)
and (t6.a != t7.a)/* and (t7.a != t8.a)*/ and (t8.a != t9.a) and (t9.a != t10.a)
and (t10.a != t11.a) and (t11.a != t12.a) and (t12.a != t13.a) and (t13.a != t14.a)
and (t14.a != t15.a) and (t15.a != t16.a) and (t16.a != t17.a) and (t17.a != t18.a) 
 and (t18.a != t19.a) and (t19.a != t20.a)
)
or (t2.a = 3 and (t8.a = t9.a)
and (t1.a != t2.a) and (t2.a != t3.a) and (t4.a != t5.a) and (t5.a != t6.a)
and (t6.a != t7.a) and (t7.a != t8.a)/* and (t8.a != t9.a)*/ and (t9.a != t10.a)
and (t10.a != t11.a) and (t11.a != t12.a) and (t12.a != t13.a) and (t13.a != t14.a)
and (t14.a != t15.a) and (t15.a != t16.a) and (t16.a != t17.a) and (t17.a != t18.a) 
 and (t18.a != t19.a) and (t19.a != t20.a))
or (t2.a = 4 and (t9.a = t10.a)
and (t1.a != t2.a) and (t2.a != t3.a) and (t4.a != t5.a) and (t5.a != t6.a)
and (t6.a != t7.a) and (t7.a != t8.a) and (t8.a != t9.a) /*and (t9.a != t10.a)*/
and (t10.a != t11.a) and (t11.a != t12.a) and (t12.a != t13.a) and (t13.a != t14.a)
and (t14.a != t15.a) and (t15.a != t16.a) and (t16.a != t17.a) and (t17.a != t18.a) 
 and (t18.a != t19.a) and (t19.a != t20.a)
)
or (t2.a = 5 and (T10.a = t11.a)
and (t1.a != t2.a) and (t2.a != t3.a) and (t4.a != t5.a) and (t5.a != t6.a)
and (t6.a != t7.a) and (t7.a != t8.a) and (t8.a != t9.a) and (t9.a != t10.a)
/*and (t10.a != t11.a)*/ and (t11.a != t12.a) and (t12.a != t13.a) and (t13.a != t14.a)
and (t14.a != t15.a) and (t15.a != t16.a) and (t16.a != t17.a) and (t17.a != t18.a) 
 and (t18.a != t19.a) and (t19.a != t20.a)
)
) /* 2 */ 
and
(
  t3.a = 1 + (case when t1.a = 5 then 1 else 0 end
+ case when t2.a = 5 then 1 else 0 end
+ case when t3.a = 5 then 1 else 0 end
+ case when t4.a = 5 then 1 else 0 end
+ case when t5.a = 5 then 1 else 0 end
+ case when t6.a = 5 then 1 else 0 end
+ case when t7.a = 5 then 1 else 0 end
+ case when t8.a = 5 then 1 else 0 end
+ case when t9.a = 5 then 1 else 0 end
+ case when t10.a = 5 then 1 else 0 end
+ case when t11.a = 5 then 1 else 0 end
+ case when t12.a = 5 then 1 else 0 end
+ case when t13.a = 5 then 1 else 0 end
+ case when t14.a = 5 then 1 else 0 end
+ case when t15.a = 5 then 1 else 0 end
+ case when t16.a = 5 then 1 else 0 end
+ case when t17.a = 5 then 1 else 0 end
+ case when t18.a = 5 then 1 else 0 end
+ case when t19.a = 5 then 1 else 0 end
+ case when t20.a = 5 then 1 else 0 end) 
) /* 3 */
and
(
t4.a + 3 = (case when t1.a = 1 then 1 else 0 end
+ case when t2.a = 1 then 1 else 0 end
+ case when t3.a = 1 then 1 else 0 end
+ case when t4.a = 1 then 1 else 0 end
+ case when t5.a = 1 then 1 else 0 end
+ case when t6.a = 1 then 1 else 0 end
+ case when t7.a = 1 then 1 else 0 end
+ case when t8.a = 1 then 1 else 0 end
+ case when t9.a = 1 then 1 else 0 end
+ case when t10.a = 1 then 1 else 0 end
+ case when t11.a = 1 then 1 else 0 end
+ case when t12.a = 1 then 1 else 0 end
+ case when t13.a = 1 then 1 else 0 end
+ case when t14.a = 1 then 1 else 0 end
+ case when t15.a = 1 then 1 else 0 end
+ case when t16.a = 1 then 1 else 0 end
+ case when t17.a = 1 then 1 else 0 end
+ case when t18.a = 1 then 1 else 0 end
+ case when t19.a = 1 then 1 else 0 end
+ case when t20.a = 1 then 1 else 0 end)
) /* 4 */
and
(
(t5.a = t1.a and t1.a = 1)
or (t5.a = t2.a and t2.a = 2)
or (t5.a = t3.a and t3.a = 3)
or (t5.a = t4.a and t4.a = 4)
or (t5.a = t5.a and t5.a = 5)  
) /* 5 */
and
(
    (t6.a = 1 and t17.a = 3)
or (t6.a = 2 and t17.a = 4)
or (t6.a = 3 and t17.a = 5)
or (t6.a = 4 and not t17.a in (3, 4, 5))
) /* 6 */
and
(
(5 - t7.a) = abs(t7.a - t8.a)
) /* 7 */
and
(
  t8.a + 3 = 
  (case when t1.a in (1, 5) then 1 else 0 end
+ case when t2.a in (1, 5) then 1 else 0 end
+ case when t3.a in (1, 5) then 1 else 0 end
+ case when t4.a in (1, 5) then 1 else 0 end
+ case when t5.a in (1, 5) then 1 else 0 end
+ case when t6.a in (1, 5) then 1 else 0 end
+ case when t7.a in (1, 5) then 1 else 0 end
+ case when t8.a in (1, 5) then 1 else 0 end
+ case when t9.a in (1, 5) then 1 else 0 end
+ case when t10.a in (1, 5) then 1 else 0 end
+ case when t11.a in (1, 5) then 1 else 0 end
+ case when t12.a in (1, 5) then 1 else 0 end
+ case when t13.a in (1, 5) then 1 else 0 end
+ case when t14.a in (1, 5) then 1 else 0 end
+ case when t15.a in (1, 5) then 1 else 0 end
+ case when t16.a in (1, 5) then 1 else 0 end
+ case when t17.a in (1, 5) then 1 else 0 end
+ case when t18.a in (1, 5) then 1 else 0 end
+ case when t19.a in (1, 5) then 1 else 0 end
+ case when t20.a in (1, 5) then 1 else 0 end)
) /* 8 */
and
(
    (t9.a = 1 and t10.a = 1)
or (t9.a = 2 and t11.a = 2)
or (t9.a = 3 and t12.a = 3)
or (t9.a = 4 and t13.a = 4)
or (t9.a = 5 and t14.a = 5)
) /* 9 */
and
(
    (t10.a = 1 and t16.a = 4)
or (t10.a = 2 and t16.a = 1)
or (t10.a = 3 and t16.a = 5)
or (t10.a = 4 and t16.a = 2)
or (t10.a = 5 and t16.a = 3)
) /* 10 */
and
(
  t11.a = 1 +
(case when t1.a = 2 then 1 else 0 end
+ case when t2.a = 2 then 1 else 0 end
+ case when t3.a = 2 then 1 else 0 end
+ case when t4.a = 2 then 1 else 0 end
+ case when t5.a = 2 then 1 else 0 end
+ case when t6.a = 2 then 1 else 0 end
+ case when t7.a = 2 then 1 else 0 end
+ case when t8.a = 2 then 1 else 0 end
+ case when t9.a = 2 then 1 else 0 end
+ case when t10.a = 2 then 1 else 0 end)
) /* 11 */
and
(
(t12.a = 1 and (case when t1.a in (2, 3, 4) then 1 else 0 end
+ case when t2.a in (2, 3, 4) then 1 else 0 end
+ case when t3.a in (2, 3, 4) then 1 else 0 end
+ case when t4.a in (2, 3, 4) then 1 else 0 end
+ case when t5.a in (2, 3, 4) then 1 else 0 end
+ case when t6.a in (2, 3, 4) then 1 else 0 end
+ case when t7.a in (2, 3, 4) then 1 else 0 end
+ case when t8.a in (2, 3, 4) then 1 else 0 end
+ case when t9.a in (2, 3, 4) then 1 else 0 end
+ case when t10.a in (2, 3, 4) then 1 else 0 end
+ case when t11.a in (2, 3, 4) then 1 else 0 end
+ case when t12.a in (2, 3, 4) then 1 else 0 end
+ case when t13.a in (2, 3, 4) then 1 else 0 end
+ case when t14.a in (2, 3, 4) then 1 else 0 end
+ case when t15.a in (2, 3, 4) then 1 else 0 end
+ case when t16.a in (2, 3, 4) then 1 else 0 end
+ case when t17.a in (2, 3, 4) then 1 else 0 end
+ case when t18.a in (2, 3, 4) then 1 else 0 end
+ case when t19.a in (2, 3, 4) then 1 else 0 end
+ case when t20.a in (2, 3, 4) then 1 else 0 end) % 2 = 0
) 
 or (t1.a = 2 and (case when t1.a in (2, 3, 4) then 1 else 0 end
+ case when t2.a in (2, 3, 4) then 1 else 0 end
+ case when t3.a in (2, 3, 4) then 1 else 0 end
+ case when t4.a in (2, 3, 4) then 1 else 0 end
+ case when t5.a in (2, 3, 4) then 1 else 0 end
+ case when t6.a in (2, 3, 4) then 1 else 0 end
+ case when t7.a in (2, 3, 4) then 1 else 0 end
+ case when t8.a in (2, 3, 4) then 1 else 0 end
+ case when t9.a in (2, 3, 4) then 1 else 0 end
+ case when t10.a in (2, 3, 4) then 1 else 0 end
+ case when t11.a in (2, 3, 4) then 1 else 0 end
+ case when t12.a in (2, 3, 4) then 1 else 0 end
+ case when t13.a in (2, 3, 4) then 1 else 0 end
+ case when t14.a in (2, 3, 4) then 1 else 0 end
+ case when t15.a in (2, 3, 4) then 1 else 0 end
+ case when t16.a in (2, 3, 4) then 1 else 0 end
+ case when t17.a in (2, 3, 4) then 1 else 0 end
+ case when t18.a in (2, 3, 4) then 1 else 0 end
+ case when t19.a in (2, 3, 4) then 1 else 0 end
+ case when t20.a in (2, 3, 4) then 1 else 0 end) % 2 = 1
) 
 or (t1.a = 3 and (case when t1.a in (2, 3, 4) then 1 else 0 end
+ case when t2.a in (2, 3, 4) then 1 else 0 end
+ case when t3.a in (2, 3, 4) then 1 else 0 end
+ case when t4.a in (2, 3, 4) then 1 else 0 end
+ case when t5.a in (2, 3, 4) then 1 else 0 end
+ case when t6.a in (2, 3, 4) then 1 else 0 end
+ case when t7.a in (2, 3, 4) then 1 else 0 end
+ case when t8.a in (2, 3, 4) then 1 else 0 end
+ case when t9.a in (2, 3, 4) then 1 else 0 end
+ case when t10.a in (2, 3, 4) then 1 else 0 end
+ case when t11.a in (2, 3, 4) then 1 else 0 end
+ case when t12.a in (2, 3, 4) then 1 else 0 end
+ case when t13.a in (2, 3, 4) then 1 else 0 end
+ case when t14.a in (2, 3, 4) then 1 else 0 end
+ case when t15.a in (2, 3, 4) then 1 else 0 end
+ case when t16.a in (2, 3, 4) then 1 else 0 end
+ case when t17.a in (2, 3, 4) then 1 else 0 end
+ case when t18.a in (2, 3, 4) then 1 else 0 end
+ case when t19.a in (2, 3, 4) then 1 else 0 end
+ case when t20.a in (2, 3, 4) then 1 else 0 end) in (1, 4)
) 
 or (t1.a = 4 and (case when t1.a in (2, 3, 4) then 1 else 0 end
+ case when t2.a in (2, 3, 4) then 1 else 0 end
+ case when t3.a in (2, 3, 4) then 1 else 0 end
+ case when t4.a in (2, 3, 4) then 1 else 0 end
+ case when t5.a in (2, 3, 4) then 1 else 0 end
+ case when t6.a in (2, 3, 4) then 1 else 0 end
+ case when t7.a in (2, 3, 4) then 1 else 0 end
+ case when t8.a in (2, 3, 4) then 1 else 0 end
+ case when t9.a in (2, 3, 4) then 1 else 0 end
+ case when t10.a in (2, 3, 4) then 1 else 0 end
+ case when t11.a in (2, 3, 4) then 1 else 0 end
+ case when t12.a in (2, 3, 4) then 1 else 0 end
+ case when t13.a in (2, 3, 4) then 1 else 0 end
+ case when t14.a in (2, 3, 4) then 1 else 0 end
+ case when t15.a in (2, 3, 4) then 1 else 0 end
+ case when t16.a in (2, 3, 4) then 1 else 0 end
+ case when t17.a in (2, 3, 4) then 1 else 0 end
+ case when t18.a in (2, 3, 4) then 1 else 0 end
+ case when t19.a in (2, 3, 4) then 1 else 0 end
+ case when t20.a in (2, 3, 4) then 1 else 0 end)  in (2, 3, 5)
)
or (t1.a = 5 and (case when t1.a in (2, 3, 4) then 1 else 0 end
+ case when t2.a in (2, 3, 4) then 1 else 0 end
+ case when t3.a in (2, 3, 4) then 1 else 0 end
+ case when t4.a in (2, 3, 4) then 1 else 0 end
+ case when t5.a in (2, 3, 4) then 1 else 0 end
+ case when t6.a in (2, 3, 4) then 1 else 0 end
+ case when t7.a in (2, 3, 4) then 1 else 0 end
+ case when t8.a in (2, 3, 4) then 1 else 0 end
+ case when t9.a in (2, 3, 4) then 1 else 0 end
+ case when t10.a in (2, 3, 4) then 1 else 0 end
+ case when t11.a in (2, 3, 4) then 1 else 0 end
+ case when t12.a in (2, 3, 4) then 1 else 0 end
+ case when t13.a in (2, 3, 4) then 1 else 0 end
+ case when t14.a in (2, 3, 4) then 1 else 0 end
+ case when t15.a in (2, 3, 4) then 1 else 0 end
+ case when t16.a in (2, 3, 4) then 1 else 0 end
+ case when t17.a in (2, 3, 4) then 1 else 0 end
+ case when t18.a in (2, 3, 4) then 1 else 0 end
+ case when t19.a in (2, 3, 4) then 1 else 0 end
+ case when t20.a in (2, 3, 4) then 1 else 0 end) = 5
) 
) /* 12 */
and
(
t1.a != 1 and t3.a != 1  and t5.a != 1  and t7.a != 1 and t19.a != 1 and 
 (
     t13.a = 1 and (t9.a = 1  and t11.a != 1  and t13.a != 1 and t15.a != 1 and t17.a != 1 and t19.a != 1)
  or t13.a = 2 and (t9.a != 1  and t11.a = 1  and t13.a != 1 and t15.a != 1 and t17.a != 1 and t19.a != 1)
  or t13.a = 3 and (t9.a != 1  and t11.a != 1  and t13.a = 1 and t15.a != 1 and t17.a != 1 and t19.a != 1)
  or t13.a = 4 and (t9.a != 1  and t11.a != 1  and t13.a != 1 and t15.a = 1 and t17.a != 1 and t19.a != 1)
  or t13.a = 5 and (t9.a != 1  and t11.a != 1  and t13.a != 1 and t15.a != 1 and t17.a = 1 )
)
) /* 13 */
and
(
t14.a = (case when t1.a = 4 then 1 else 0 end
+ case when t2.a = 4 then 1 else 0 end
+ case when t3.a = 4 then 1 else 0 end
+ case when t4.a = 4 then 1 else 0 end
+ case when t5.a = 4 then 1 else 0 end
+ case when t6.a = 4 then 1 else 0 end
+ case when t7.a = 4 then 1 else 0 end
+ case when t8.a = 4 then 1 else 0 end
+ case when t9.a = 4 then 1 else 0 end
+ case when t10.a = 4 then 1 else 0 end
+ case when t11.a = 4 then 1 else 0 end
+ case when t12.a = 4 then 1 else 0 end
+ case when t13.a = 4 then 1 else 0 end
+ case when t14.a = 4 then 1 else 0 end
+ case when t15.a = 4 then 1 else 0 end
+ case when t16.a = 4 then 1 else 0 end
+ case when t17.a = 4 then 1 else 0 end
+ case when t18.a = 4 then 1 else 0 end
+ case when t19.a = 4 then 1 else 0 end
+ case when t20.a = 4 then 1 else 0 end) - 5
) /* 14 */
and
(
t15.a = t12.a
) /* 15 */
and
(
    (t16.a = 1 and t10.a = 4)
or (t16.a = 2 and t10.a = 3)
or (t16.a = 3 and t10.a = 2)
or (t16.a = 4 and t10.a = 1)
or (t16.a = 5 and t10.a = 5)
) /* 16 */
and
(
   (t17.a = 1 and t6.a = 3)
or (t17.a = 2 and t6.a = 4)
or (t17.a = 3 and t6.a = 5)
or (t17.a = 4 and not t6.a in (3, 4, 5)) 
) /* 17 */
<p>and
(
(t18.a = 1 and
((case when t1.a = 1 then 1 else 0 end</p>
<ul>
<li>case when t2.a = 1 then 1 else 0 end</li>
<li>case when t3.a = 1 then 1 else 0 end</li>
<li>case when t4.a = 1 then 1 else 0 end</li>
<li>case when t5.a = 1 then 1 else 0 end</li>
<li>case when t6.a = 1 then 1 else 0 end</li>
<li>case when t7.a = 1 then 1 else 0 end</li>
<li>case when t8.a = 1 then 1 else 0 end</li>
<li>case when t9.a = 1 then 1 else 0 end</li>
<li>case when t10.a = 1 then 1 else 0 end</li>
<li>case when t11.a = 1 then 1 else 0 end</li>
<li>case when t12.a = 1 then 1 else 0 end</li>
<li>case when t13.a = 1 then 1 else 0 end</li>
<li>case when t14.a = 1 then 1 else 0 end</li>
<li>case when t15.a = 1 then 1 else 0 end</li>
<li>case when t16.a = 1 then 1 else 0 end</li>
<li>case when t17.a = 1 then 1 else 0 end</li>
<li>case when t18.a = 1 then 1 else 0 end</li>
<li>case when t19.a = 1 then 1 else 0 end</li>
<li>case when t20.a = 1 then 1 else 0 end) =
(case when t1.a = 2 then 1 else 0 end</li>
<li>case when t2.a = 2 then 1 else 0 end</li>
<li>case when t3.a = 2 then 1 else 0 end</li>
<li>case when t4.a = 2 then 1 else 0 end</li>
<li>case when t5.a = 2 then 1 else 0 end</li>
<li>case when t6.a = 2 then 1 else 0 end</li>
<li>case when t7.a = 2 then 1 else 0 end</li>
<li>case when t8.a = 2 then 1 else 0 end</li>
<li>case when t9.a = 2 then 1 else 0 end</li>
<li>case when t10.a = 2 then 1 else 0 end</li>
<li>case when t11.a = 2 then 1 else 0 end</li>
<li>case when t12.a = 2 then 1 else 0 end</li>
<li>case when t13.a = 2 then 1 else 0 end</li>
<li>case when t14.a = 2 then 1 else 0 end</li>
<li>case when t15.a = 2 then 1 else 0 end</li>
<li>case when t16.a = 2 then 1 else 0 end</li>
<li>case when t17.a = 2 then 1 else 0 end</li>
<li>case when t18.a = 2 then 1 else 0 end</li>
<li>case when t19.a = 2 then 1 else 0 end</li>
<li>case when t20.a = 2 then 1 else 0 end)))
or (t18.a = 2 and
((case when t1.a = 1 then 1 else 0 end</li>
<li>case when t2.a = 1 then 1 else 0 end</li>
<li>case when t3.a = 1 then 1 else 0 end</li>
<li>case when t4.a = 1 then 1 else 0 end</li>
<li>case when t5.a = 1 then 1 else 0 end</li>
<li>case when t6.a = 1 then 1 else 0 end</li>
<li>case when t7.a = 1 then 1 else 0 end</li>
<li>case when t8.a = 1 then 1 else 0 end</li>
<li>case when t9.a = 1 then 1 else 0 end</li>
<li>case when t10.a = 1 then 1 else 0 end</li>
<li>case when t11.a = 1 then 1 else 0 end</li>
<li>case when t12.a = 1 then 1 else 0 end</li>
<li>case when t13.a = 1 then 1 else 0 end</li>
<li>case when t14.a = 1 then 1 else 0 end</li>
<li>case when t15.a = 1 then 1 else 0 end</li>
<li>case when t16.a = 1 then 1 else 0 end</li>
<li>case when t17.a = 1 then 1 else 0 end</li>
<li>case when t18.a = 1 then 1 else 0 end</li>
<li>case when t19.a = 1 then 1 else 0 end</li>
<li>case when t20.a = 1 then 1 else 0 end) =
(case when t1.a = 3 then 1 else 0 end</li>
<li>case when t2.a = 3 then 1 else 0 end</li>
<li>case when t3.a = 3 then 1 else 0 end</li>
<li>case when t4.a = 3 then 1 else 0 end</li>
<li>case when t5.a = 3 then 1 else 0 end</li>
<li>case when t6.a = 3 then 1 else 0 end</li>
<li>case when t7.a = 3 then 1 else 0 end</li>
<li>case when t8.a = 3 then 1 else 0 end</li>
<li>case when t9.a = 3 then 1 else 0 end</li>
<li>case when t10.a = 3 then 1 else 0 end</li>
<li>case when t11.a = 3 then 1 else 0 end</li>
<li>case when t12.a = 3 then 1 else 0 end</li>
<li>case when t13.a = 3 then 1 else 0 end</li>
<li>case when t14.a = 3 then 1 else 0 end</li>
<li>case when t15.a = 3 then 1 else 0 end</li>
<li>case when t16.a = 3 then 1 else 0 end</li>
<li>case when t17.a = 3 then 1 else 0 end</li>
<li>case when t18.a = 3 then 1 else 0 end</li>
<li>case when t19.a = 3 then 1 else 0 end</li>
<li>case when t20.a = 3 then 1 else 0 end)))
or (t18.a = 3 and
((case when t1.a = 1 then 1 else 0 end</li>
<li>case when t2.a = 1 then 1 else 0 end</li>
<li>case when t3.a = 1 then 1 else 0 end</li>
<li>case when t4.a = 1 then 1 else 0 end</li>
<li>case when t5.a = 1 then 1 else 0 end</li>
<li>case when t6.a = 1 then 1 else 0 end</li>
<li>case when t7.a = 1 then 1 else 0 end</li>
<li>case when t8.a = 1 then 1 else 0 end</li>
<li>case when t9.a = 1 then 1 else 0 end</li>
<li>case when t10.a = 1 then 1 else 0 end</li>
<li>case when t11.a = 1 then 1 else 0 end</li>
<li>case when t12.a = 1 then 1 else 0 end</li>
<li>case when t13.a = 1 then 1 else 0 end</li>
<li>case when t14.a = 1 then 1 else 0 end</li>
<li>case when t15.a = 1 then 1 else 0 end</li>
<li>case when t16.a = 1 then 1 else 0 end</li>
<li>case when t17.a = 1 then 1 else 0 end</li>
<li>case when t18.a = 1 then 1 else 0 end</li>
<li>case when t19.a = 1 then 1 else 0 end</li>
<li>case when t20.a = 1 then 1 else 0 end) =
(case when t1.a = 4 then 1 else 0 end</li>
<li>case when t2.a = 4 then 1 else 0 end</li>
<li>case when t3.a = 4 then 1 else 0 end</li>
<li>case when t4.a = 4 then 1 else 0 end</li>
<li>case when t5.a = 4 then 1 else 0 end</li>
<li>case when t6.a = 4 then 1 else 0 end</li>
<li>case when t7.a = 4 then 1 else 0 end</li>
<li>case when t8.a = 4 then 1 else 0 end</li>
<li>case when t9.a = 4 then 1 else 0 end</li>
<li>case when t10.a = 4 then 1 else 0 end</li>
<li>case when t11.a = 4 then 1 else 0 end</li>
<li>case when t12.a = 4 then 1 else 0 end</li>
<li>case when t13.a = 4 then 1 else 0 end</li>
<li>case when t14.a = 4 then 1 else 0 end</li>
<li>case when t15.a = 4 then 1 else 0 end</li>
<li>case when t16.a = 4 then 1 else 0 end</li>
<li>case when t17.a = 4 then 1 else 0 end</li>
<li>case when t18.a = 4 then 1 else 0 end</li>
<li>case when t19.a = 4 then 1 else 0 end</li>
<li>case when t20.a = 4 then 1 else 0 end)))
or (t18.a = 4 and
((case when t1.a = 1 then 1 else 0 end</li>
<li>case when t2.a = 1 then 1 else 0 end</li>
<li>case when t3.a = 1 then 1 else 0 end</li>
<li>case when t4.a = 1 then 1 else 0 end</li>
<li>case when t5.a = 1 then 1 else 0 end</li>
<li>case when t6.a = 1 then 1 else 0 end</li>
<li>case when t7.a = 1 then 1 else 0 end</li>
<li>case when t8.a = 1 then 1 else 0 end</li>
<li>case when t9.a = 1 then 1 else 0 end</li>
<li>case when t10.a = 1 then 1 else 0 end</li>
<li>case when t11.a = 1 then 1 else 0 end</li>
<li>case when t12.a = 1 then 1 else 0 end</li>
<li>case when t13.a = 1 then 1 else 0 end</li>
<li>case when t14.a = 1 then 1 else 0 end</li>
<li>case when t15.a = 1 then 1 else 0 end</li>
<li>case when t16.a = 1 then 1 else 0 end</li>
<li>case when t17.a = 1 then 1 else 0 end</li>
<li>case when t18.a = 1 then 1 else 0 end</li>
<li>case when t19.a = 1 then 1 else 0 end</li>
<li>case when t20.a = 1 then 1 else 0 end) =
(case when t1.a = 5 then 1 else 0 end</li>
<li>case when t2.a = 5 then 1 else 0 end</li>
<li>case when t3.a = 5 then 1 else 0 end</li>
<li>case when t4.a = 5 then 1 else 0 end</li>
<li>case when t5.a = 5 then 1 else 0 end</li>
<li>case when t6.a = 5 then 1 else 0 end</li>
<li>case when t7.a = 5 then 1 else 0 end</li>
<li>case when t8.a = 5 then 1 else 0 end</li>
<li>case when t9.a = 5 then 1 else 0 end</li>
<li>case when t10.a = 5 then 1 else 0 end</li>
<li>case when t11.a = 5 then 1 else 0 end</li>
<li>case when t12.a = 5 then 1 else 0 end</li>
<li>case when t13.a = 5 then 1 else 0 end</li>
<li>case when t14.a = 5 then 1 else 0 end</li>
<li>case when t15.a = 5 then 1 else 0 end</li>
<li>case when t16.a = 5 then 1 else 0 end</li>
<li>case when t17.a = 5 then 1 else 0 end</li>
<li>case when t18.a = 5 then 1 else 0 end</li>
<li>case when t19.a = 5 then 1 else 0 end</li>
<li>case when t20.a = 5 then 1 else 0 end)))
) /* 18 */
</pre></lj-spoiler></li>
</ul>
<p>
Logical  puzzles are not frequently being part of enterprise application, but I found it really assuring that SQL engine can work on my WHERE clauses with such effectivenes.</p>]]></content:encoded></item><item><title>Coursera.org и функциональное программирование</title><link>https://konstantin.gladyou.click/posts/2013-04-03-coursera-org/</link><pubDate>Wed, 03 Apr 2013 00:25:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2013-04-03-coursera-org/</guid><description>Совсем недавно завершил курс по функциональному программированию на coursera.org. По этому поводу очень сильно радуюсь и хвастаюсь сертификатом в своём основном блоге. Конечно, получил кучу новых знаний и навыков, но любопытно другое. Я первоначально хотел освоить ФП и внедрить его на своём текущем проекте. То есть добавлять потихоньку модули на F# для решения тех задач, где ФП к месту.
Так вот забавным было то, что оказалось, что большая часть функциональных вещей доступна в самом C# безо всякого F#.</description><content:encoded><![CDATA[<p>Совсем недавно завершил курс по функциональному программированию на <a href="http://coursera.org">coursera.org</a>. По этому поводу очень сильно радуюсь и хвастаюсь сертификатом в своём основном <a href="http://bukov-ka.livejournal.com/86412.html">блоге</a>. Конечно, получил кучу новых знаний и навыков, но любопытно другое. Я первоначально хотел освоить ФП и внедрить его на своём текущем проекте. То есть добавлять потихоньку модули на F# для решения тех задач, где ФП к месту.</p>
<p>Так вот забавным было то, что оказалось, что большая часть функциональных вещей доступна в самом C# безо всякого F#. То есть хочешь создать функцию с помощью лямбда-выражения — пожалуйста. Хочешь использовать замыкание в ней — никто не против. Передать как параметр или вернуть функцию из функции — на здоровье. Оказалось, что горячо любимый мной LinqToObjects является по сути воплощением идей ФП в объектно-ориентированном C#. И реализовывать наиболее естественные для ФП вещи проще в C#, не меняя язык.</p>
<p>Конечно, синтаксис местами выглядит страшновато и, например, понравившегося мне матчинга нет, но пока какой-то хорошей области, куда я могу прямо сейчас в работе применить F# я не вижу. Наверное, если удастся выделить кусок побольше, со своими структурами данных и прочим, то смысл появится. Буду потихоньку продолжать изучение и думать.</p>
]]></content:encoded></item><item><title>Пишем формулы Excel</title><link>https://konstantin.gladyou.click/posts/2011-10-17-excel/</link><pubDate>Mon, 17 Oct 2011 21:16:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2011-10-17-excel/</guid><description>&lt;p>Снова удалось прочитать доклад в омской &lt;a href="http://www.facebook.com/groups/152767728078777/">юзер-группе&lt;/a>. Мне последнее время стало казаться, что &amp;ldquo;обычный&amp;rdquo; формат доклада с набором последовательных слайдов очень ограничен, поэтому в этот раз я попытался просто писать код и говорить. А в качестве примера я выбрал реализацию грида с формулами.&lt;/p></description><content:encoded><![CDATA[<p>Снова удалось прочитать доклад в омской <a href="http://www.facebook.com/groups/152767728078777/">юзер-группе</a>. Мне последнее время стало казаться, что &ldquo;обычный&rdquo; формат доклада с набором последовательных слайдов очень ограничен, поэтому в этот раз я попытался просто писать код и говорить. А в качестве примера я выбрал реализацию грида с формулами.</p>
<p>Как ни удивительно, но в моей практике было два случая, когда заказчики хотели &ldquo;формулки, как в Экселе&rdquo;. Правда, PMы всегда мужественно и непреклонно от этих хотелок отбивались. Но мне всегда мечталось попробовать такое написать. Вот и попробовал.</p>
<p>Конечно, написание более-менее законченного приложения для часового доклада &ndash; это чересчур. Поэтому я взял заготовку с уже работающим гридом, подготовленным для &ldquo;прикручивания&rdquo; к нему формул, и реально реализовывал только сам движок формул.</p>
<p>Чтобы было понятно, как оно выглядит, покажу:
<img src="https://konstantin.gladyou.click/konstantin/bukov_net_pic_0000fcw2.jpg"/></p>
<p>По-правильному, надо было бы, наверное, писать какой-то парсер формул (с помощью, например, ANTLR), но этот путь казался слишком сложным. Поэтому я решил просто на лету генерировать класс, имеющий на каждую ячейку по публичному свойству (с говорящими именами A1, A2,&hellip;). Простые ячейки просто содержали единственный return значения, а ячейки с формулами &ndash; тупо возвращали текст формулы (например, &ldquo;return A1+A2&rdquo;, если формула была &ldquo;=A1+A2&rdquo;).</p>
<p>Этот класс я компилировал на лету с помощью CodeDomProvider, и общался с ним через Reflection. Очень просто и наглядно. Компиляция занимает порядка 0.1с, но необходима не всегда, если формулы не меняются, то обновлённые данные можно подсовывать также через Reflection.</p>
<p>Самое удивительное даже не то, что всё это работает, а то, что функционирующее ядро оказалось вполне возможно написать за 40 минут! Кому интересно, может скачать <a href="http://katpop.narod.ru/files/jj/exclgrid.zip">пример</a>.</p>
<p>Использовать код из архива напрямую в продуктиве я настоятельно не рекомендую, так как и сам грид реализован весьма криво и вычислительное ядро забивает память кучей генерируемых сборок. Но для иллюстрации идеи &ndash; вполне.</p>
<p>Мне, конечно, была забавна сама идея динамической генерации кода. Раньше я такое встречал в интерпретаторах. По-моему, технология вполне применима на практике. Сгенерированный код работает быстро, так что можно переводить какие-то чужеродные структуры на язык C#. Например, компилировать нейронные сети. Или писать свой язык программирования.</p>
<p>На практике, конечно, наиболее логично применять динамическую компиляцию в каких-то инструментах для программистов. Например, в утилитах вроде LINQPad &ndash; самое место. А в целом хотелось донести мысль, что если давать волю фантазии, то можно свернуть горы. Ну или хотя бы разнообразить себе жизнь.</p>]]></content:encoded></item><item><title>Форматирование исходного кода из Visual Studio в HTML</title><link>https://konstantin.gladyou.click/posts/2011-07-16-visual-studio-html/</link><pubDate>Sat, 16 Jul 2011 18:55:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2011-07-16-visual-studio-html/</guid><description>&lt;p>Мне в блоге периодически приходится писать какой-то исходный код на C#. При этом хочется, чтобы код был красиво раскрашен так, как я вижу его в Visual Studio. Первое время мучался с парой каких-то средств форматирования, но они мне не нравились. Вставлять в Word, а потом экспортировать как HTML &amp;ndash; ужас и кошмар, получаются многокилометровые куски абсолютно нечитаемой разметки. Поэтому решил написать по-быстрому соответствующую утилитку.&lt;/p></description><content:encoded><![CDATA[<p>Мне в блоге периодически приходится писать какой-то исходный код на C#. При этом хочется, чтобы код был красиво раскрашен так, как я вижу его в Visual Studio. Первое время мучался с парой каких-то средств форматирования, но они мне не нравились. Вставлять в Word, а потом экспортировать как HTML &ndash; ужас и кошмар, получаются многокилометровые куски абсолютно нечитаемой разметки. Поэтому решил написать по-быстрому соответствующую утилитку.</p>
<p>Решил использовать тот факт, что в Visual Studio можно скопировать кусок кода и при этом в буфере обмена он будет красивенький, с форматированием. Получить кусок из буфера обмена, вставить его в RichTextBox и пробежаться по символам, отслеживая изменение цвета &ndash; дело несложное:</p>
<pre style="color:black">
 <span style="color:#2B91AF;">MemoryStream</span> stream = <span style="color:Blue;">new</span> <span style="color:#2B91AF;">MemoryStream</span>(<span style="color:#2B91AF;">ASCIIEncoding</span>.Default.GetBytes(str));
            richTextBox.LoadFile(stream, <span style="color:#2B91AF;">RichTextBoxStreamType</span>.RichText);
            <span style="color:#2B91AF;">Color</span> lastColor = <span style="color:#2B91AF;">Color</span>.Black; <span style="color:Green;">// Black font by default</span>
            <span style="color:#2B91AF;">StringBuilder</span> htmlBuilder = <span style="color:Blue;">new</span> <span style="color:#2B91AF;">StringBuilder</span>(); <span style="color:Green;">// Result HTML</span>
            htmlBuilder.AppendLine(<span style="color:#A31515;">"&lt;pre style=\"color:black\"&gt;"</span>); <span style="color:Green;">// Open &lt;pre&gt;-element for source code</span>
            <span style="color:Blue;">for</span>(<span style="color:Blue;">int</span> i=0; i&lt; richTextBox.Text.Length; i++)
            {
                richTextBox.Select(i, 1);
                <span style="color:#2B91AF;">Color</span> currentColor = richTextBox.SelectionColor;
                <span style="color:Blue;">if</span> (lastColor != currentColor)
                {
                    <span style="color:Blue;">if</span> (lastColor != <span style="color:#2B91AF;">Color</span>.Black) <span style="color:Green;">// There was open colo span, we need to close it</span>
                    {
                        htmlBuilder.Append(<span style="color:#A31515;">"&lt;/span&gt;"</span>);
                    }
                    lastColor = currentColor; <span style="color:Green;">// Store color value</span>
                    <span style="color:Blue;">if</span> (currentColor != <span style="color:#2B91AF;">Color</span>.Black) <span style="color:Green;">// Black color is default. Don't mark it</span>
                    {

                        <span style="color:Green;">// Open span element with color specified</span>
                        htmlBuilder.Append
                            (
                                <span style="color:Blue;">string</span>.Format
                                (<span style="color:#A31515;">"&lt;span style=\"color:{0};\"&gt;"</span>,
                                    currentColor.IsKnownColor ?
                                    currentColor.Name :
                                    <span style="color:Blue;">string</span>.Format(<span style="color:#A31515;">"#{0:X}{1:X}{2:X}"</span>, currentColor.R, currentColor.G, currentColor.B)
                                 )
                             );
                    }
                }
                <span style="color:Blue;">string</span> currentSymbol = richTextBox.SelectedText;
                <span style="color:Green;">// Simple HTMLEncode</span>
                currentSymbol = currentSymbol.Replace(<span style="color:#A31515;">"&amp;"</span>, <span style="color:#A31515;">"&amp;amp;"</span>);
                currentSymbol = currentSymbol.Replace(<span style="color:#A31515;">"&lt;"</span>, <span style="color:#A31515;">"&amp;lt;"</span>);
                currentSymbol = currentSymbol.Replace(<span style="color:#A31515;">"&gt;"</span>, <span style="color:#A31515;">"&amp;gt;"</span>);
                htmlBuilder.Append(currentSymbol); <span style="color:Green;">// Move one symbol</span>
            }
            htmlBuilder.AppendLine(<span style="color:#A31515;">"&lt;/pre&gt;"</span>); <span style="color:Green;">// Close &lt;pre&gt; element</pre>
<p>Исходный код этого простейшего, но полезного приложения можно <a href="http://katpop.narod.ru/files/jj/ccolorer.zip">скачать</a> и использовать.</p>]]></content:encoded></item><item><title>Вычисление логических выражений на SQL</title><link>https://konstantin.gladyou.click/posts/2011-05-14-sql/</link><pubDate>Sat, 14 May 2011 07:36:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2011-05-14-sql/</guid><description>&lt;p>kukina_kat&amp;quot; title=&amp;ldquo;Жена подкинула тут чудесную логическую задачку:
&lt;img src="https://konstantin.gladyou.click/konstantin/bukov_net_pic_0000e1fe.jpg" />
Дело это было в середине рабочего дня, поэтому фраза &amp;ldquo;Стандартизированный тест относится к интеллигентности как барометр&amp;rdquo; сразу похоронила остатки интеллектуальных мощностей. Начал распутывать условия, но очень быстро где-то ошибся и потерял нить рассуждений. После этого стал думать, как можно написать программку, которая бы думала за меня. Память тихо подсказывала использовать для решения LISP, Prolog или на худой конец F#, но этих слов я не знал. Зато подумалось, что эту задачку можно решить на SQL.&lt;/p></description><content:encoded><![CDATA[<p>kukina_kat&quot; title=&ldquo;Жена подкинула тут чудесную логическую задачку:
<img src="https://konstantin.gladyou.click/konstantin/bukov_net_pic_0000e1fe.jpg" />
Дело это было в середине рабочего дня, поэтому фраза &ldquo;Стандартизированный тест относится к интеллигентности как барометр&rdquo; сразу похоронила остатки интеллектуальных мощностей. Начал распутывать условия, но очень быстро где-то ошибся и потерял нить рассуждений. После этого стал думать, как можно написать программку, которая бы думала за меня. Память тихо подсказывала использовать для решения LISP, Prolog или на худой конец F#, но этих слов я не знал. Зато подумалось, что эту задачку можно решить на SQL.</p>
<p>SQL-выражение получилось нехилое (ЖЖ даже не позволил его опубликовать с форматированием из-за превышения лимита на размер поста):</p>
<pre style="color:black">
with t as
(select 1 as a
union
select 2
union
select 3
union
select 4
union
select 5)
select  *
  from t as t1, t as t2, t as t3, t as t4, t as t5,
                    t as t6, t as t7, t as t8, t as t9, t as t10,
                    t as t11, t as t12, t as t13, t as t14, t as t15,
                    t as t16, t as t17, t as t18, t as t19, (select 5 as a) as t20 /* Cross join */
where 
(
(t1.a = 2 and t2.a = 2)
or (t1.a = 3 and t3.a = 2)
or (t1.a = 4 and t4.a = 2)
or (t1.a = 5 and t5.a = 2)
) /* 1 */
and
(
(t2.a = 1 and (t6.a = t7.a)
and (t1.a != t2.a) and (t2.a != t3.a) and (t4.a != t5.a) and (t5.a != t6.a)
/*and (t6.a != t7.a)*/ and (t7.a != t8.a) and (t8.a != t9.a) and (t9.a != t10.a)
and (t10.a != t11.a) and (t11.a != t12.a) and (t12.a != t13.a) and (t13.a != t14.a)
and (t14.a != t15.a) and (t15.a != t16.a) and (t16.a != t17.a) and (t17.a != t18.a) 
 and (t18.a != t19.a) and (t19.a != t20.a))
 or (t2.a = 2 and (t7.a = t8.a)
and (t1.a != t2.a) and (t2.a != t3.a) and (t4.a != t5.a) and (t5.a != t6.a)
and (t6.a != t7.a)/* and (t7.a != t8.a)*/ and (t8.a != t9.a) and (t9.a != t10.a)
and (t10.a != t11.a) and (t11.a != t12.a) and (t12.a != t13.a) and (t13.a != t14.a)
and (t14.a != t15.a) and (t15.a != t16.a) and (t16.a != t17.a) and (t17.a != t18.a) 
 and (t18.a != t19.a) and (t19.a != t20.a)
)
or (t2.a = 3 and (t8.a = t9.a)
and (t1.a != t2.a) and (t2.a != t3.a) and (t4.a != t5.a) and (t5.a != t6.a)
and (t6.a != t7.a) and (t7.a != t8.a)/* and (t8.a != t9.a)*/ and (t9.a != t10.a)
and (t10.a != t11.a) and (t11.a != t12.a) and (t12.a != t13.a) and (t13.a != t14.a)
and (t14.a != t15.a) and (t15.a != t16.a) and (t16.a != t17.a) and (t17.a != t18.a) 
 and (t18.a != t19.a) and (t19.a != t20.a))
or (t2.a = 4 and (t9.a = t10.a)
and (t1.a != t2.a) and (t2.a != t3.a) and (t4.a != t5.a) and (t5.a != t6.a)
and (t6.a != t7.a) and (t7.a != t8.a) and (t8.a != t9.a) /*and (t9.a != t10.a)*/
and (t10.a != t11.a) and (t11.a != t12.a) and (t12.a != t13.a) and (t13.a != t14.a)
and (t14.a != t15.a) and (t15.a != t16.a) and (t16.a != t17.a) and (t17.a != t18.a) 
 and (t18.a != t19.a) and (t19.a != t20.a)
)
or (t2.a = 5 and (T10.a = t11.a)
and (t1.a != t2.a) and (t2.a != t3.a) and (t4.a != t5.a) and (t5.a != t6.a)
and (t6.a != t7.a) and (t7.a != t8.a) and (t8.a != t9.a) and (t9.a != t10.a)
/*and (t10.a != t11.a)*/ and (t11.a != t12.a) and (t12.a != t13.a) and (t13.a != t14.a)
and (t14.a != t15.a) and (t15.a != t16.a) and (t16.a != t17.a) and (t17.a != t18.a) 
 and (t18.a != t19.a) and (t19.a != t20.a)
)
) /* 2 */ 
and
(
  t3.a = 1 + (case when t1.a = 5 then 1 else 0 end
+ case when t2.a = 5 then 1 else 0 end
+ case when t3.a = 5 then 1 else 0 end
+ case when t4.a = 5 then 1 else 0 end
+ case when t5.a = 5 then 1 else 0 end
+ case when t6.a = 5 then 1 else 0 end
+ case when t7.a = 5 then 1 else 0 end
+ case when t8.a = 5 then 1 else 0 end
+ case when t9.a = 5 then 1 else 0 end
+ case when t10.a = 5 then 1 else 0 end
+ case when t11.a = 5 then 1 else 0 end
+ case when t12.a = 5 then 1 else 0 end
+ case when t13.a = 5 then 1 else 0 end
+ case when t14.a = 5 then 1 else 0 end
+ case when t15.a = 5 then 1 else 0 end
+ case when t16.a = 5 then 1 else 0 end
+ case when t17.a = 5 then 1 else 0 end
+ case when t18.a = 5 then 1 else 0 end
+ case when t19.a = 5 then 1 else 0 end
+ case when t20.a = 5 then 1 else 0 end) 
) /* 3 */
and
(
t4.a + 3 = (case when t1.a = 1 then 1 else 0 end
+ case when t2.a = 1 then 1 else 0 end
+ case when t3.a = 1 then 1 else 0 end
+ case when t4.a = 1 then 1 else 0 end
+ case when t5.a = 1 then 1 else 0 end
+ case when t6.a = 1 then 1 else 0 end
+ case when t7.a = 1 then 1 else 0 end
+ case when t8.a = 1 then 1 else 0 end
+ case when t9.a = 1 then 1 else 0 end
+ case when t10.a = 1 then 1 else 0 end
+ case when t11.a = 1 then 1 else 0 end
+ case when t12.a = 1 then 1 else 0 end
+ case when t13.a = 1 then 1 else 0 end
+ case when t14.a = 1 then 1 else 0 end
+ case when t15.a = 1 then 1 else 0 end
+ case when t16.a = 1 then 1 else 0 end
+ case when t17.a = 1 then 1 else 0 end
+ case when t18.a = 1 then 1 else 0 end
+ case when t19.a = 1 then 1 else 0 end
+ case when t20.a = 1 then 1 else 0 end)
) /* 4 */
and
(
(t5.a = t1.a and t1.a = 1)
or (t5.a = t2.a and t2.a = 2)
or (t5.a = t3.a and t3.a = 3)
or (t5.a = t4.a and t4.a = 4)
or (t5.a = t5.a and t5.a = 5)  
) /* 5 */
and
(
    (t6.a = 1 and t17.a = 3)
or (t6.a = 2 and t17.a = 4)
or (t6.a = 3 and t17.a = 5)
or (t6.a = 4 and not t17.a in (3, 4, 5))
) /* 6 */
and
(
(5 - t7.a) = abs(t7.a - t8.a)
) /* 7 */
and
(
  t8.a + 3 = 
  (case when t1.a in (1, 5) then 1 else 0 end
+ case when t2.a in (1, 5) then 1 else 0 end
+ case when t3.a in (1, 5) then 1 else 0 end
+ case when t4.a in (1, 5) then 1 else 0 end
+ case when t5.a in (1, 5) then 1 else 0 end
+ case when t6.a in (1, 5) then 1 else 0 end
+ case when t7.a in (1, 5) then 1 else 0 end
+ case when t8.a in (1, 5) then 1 else 0 end
+ case when t9.a in (1, 5) then 1 else 0 end
+ case when t10.a in (1, 5) then 1 else 0 end
+ case when t11.a in (1, 5) then 1 else 0 end
+ case when t12.a in (1, 5) then 1 else 0 end
+ case when t13.a in (1, 5) then 1 else 0 end
+ case when t14.a in (1, 5) then 1 else 0 end
+ case when t15.a in (1, 5) then 1 else 0 end
+ case when t16.a in (1, 5) then 1 else 0 end
+ case when t17.a in (1, 5) then 1 else 0 end
+ case when t18.a in (1, 5) then 1 else 0 end
+ case when t19.a in (1, 5) then 1 else 0 end
+ case when t20.a in (1, 5) then 1 else 0 end)
) /* 8 */
and
(
    (t9.a = 1 and t10.a = 1)
or (t9.a = 2 and t11.a = 2)
or (t9.a = 3 and t12.a = 3)
or (t9.a = 4 and t13.a = 4)
or (t9.a = 5 and t14.a = 5)
) /* 9 */
and
(
    (t10.a = 1 and t16.a = 4)
or (t10.a = 2 and t16.a = 1)
or (t10.a = 3 and t16.a = 5)
or (t10.a = 4 and t16.a = 2)
or (t10.a = 5 and t16.a = 3)
) /* 10 */
and
(
  t11.a = 1 +
(case when t1.a = 2 then 1 else 0 end
+ case when t2.a = 2 then 1 else 0 end
+ case when t3.a = 2 then 1 else 0 end
+ case when t4.a = 2 then 1 else 0 end
+ case when t5.a = 2 then 1 else 0 end
+ case when t6.a = 2 then 1 else 0 end
+ case when t7.a = 2 then 1 else 0 end
+ case when t8.a = 2 then 1 else 0 end
+ case when t9.a = 2 then 1 else 0 end
+ case when t10.a = 2 then 1 else 0 end)
) /* 11 */
and
(
(t12.a = 1 and (case when t1.a in (2, 3, 4) then 1 else 0 end
+ case when t2.a in (2, 3, 4) then 1 else 0 end
+ case when t3.a in (2, 3, 4) then 1 else 0 end
+ case when t4.a in (2, 3, 4) then 1 else 0 end
+ case when t5.a in (2, 3, 4) then 1 else 0 end
+ case when t6.a in (2, 3, 4) then 1 else 0 end
+ case when t7.a in (2, 3, 4) then 1 else 0 end
+ case when t8.a in (2, 3, 4) then 1 else 0 end
+ case when t9.a in (2, 3, 4) then 1 else 0 end
+ case when t10.a in (2, 3, 4) then 1 else 0 end
+ case when t11.a in (2, 3, 4) then 1 else 0 end
+ case when t12.a in (2, 3, 4) then 1 else 0 end
+ case when t13.a in (2, 3, 4) then 1 else 0 end
+ case when t14.a in (2, 3, 4) then 1 else 0 end
+ case when t15.a in (2, 3, 4) then 1 else 0 end
+ case when t16.a in (2, 3, 4) then 1 else 0 end
+ case when t17.a in (2, 3, 4) then 1 else 0 end
+ case when t18.a in (2, 3, 4) then 1 else 0 end
+ case when t19.a in (2, 3, 4) then 1 else 0 end
+ case when t20.a in (2, 3, 4) then 1 else 0 end) % 2 = 0
) 
 or (t1.a = 2 and (case when t1.a in (2, 3, 4) then 1 else 0 end
+ case when t2.a in (2, 3, 4) then 1 else 0 end
+ case when t3.a in (2, 3, 4) then 1 else 0 end
+ case when t4.a in (2, 3, 4) then 1 else 0 end
+ case when t5.a in (2, 3, 4) then 1 else 0 end
+ case when t6.a in (2, 3, 4) then 1 else 0 end
+ case when t7.a in (2, 3, 4) then 1 else 0 end
+ case when t8.a in (2, 3, 4) then 1 else 0 end
+ case when t9.a in (2, 3, 4) then 1 else 0 end
+ case when t10.a in (2, 3, 4) then 1 else 0 end
+ case when t11.a in (2, 3, 4) then 1 else 0 end
+ case when t12.a in (2, 3, 4) then 1 else 0 end
+ case when t13.a in (2, 3, 4) then 1 else 0 end
+ case when t14.a in (2, 3, 4) then 1 else 0 end
+ case when t15.a in (2, 3, 4) then 1 else 0 end
+ case when t16.a in (2, 3, 4) then 1 else 0 end
+ case when t17.a in (2, 3, 4) then 1 else 0 end
+ case when t18.a in (2, 3, 4) then 1 else 0 end
+ case when t19.a in (2, 3, 4) then 1 else 0 end
+ case when t20.a in (2, 3, 4) then 1 else 0 end) % 2 = 1
) 
 or (t1.a = 3 and (case when t1.a in (2, 3, 4) then 1 else 0 end
+ case when t2.a in (2, 3, 4) then 1 else 0 end
+ case when t3.a in (2, 3, 4) then 1 else 0 end
+ case when t4.a in (2, 3, 4) then 1 else 0 end
+ case when t5.a in (2, 3, 4) then 1 else 0 end
+ case when t6.a in (2, 3, 4) then 1 else 0 end
+ case when t7.a in (2, 3, 4) then 1 else 0 end
+ case when t8.a in (2, 3, 4) then 1 else 0 end
+ case when t9.a in (2, 3, 4) then 1 else 0 end
+ case when t10.a in (2, 3, 4) then 1 else 0 end
+ case when t11.a in (2, 3, 4) then 1 else 0 end
+ case when t12.a in (2, 3, 4) then 1 else 0 end
+ case when t13.a in (2, 3, 4) then 1 else 0 end
+ case when t14.a in (2, 3, 4) then 1 else 0 end
+ case when t15.a in (2, 3, 4) then 1 else 0 end
+ case when t16.a in (2, 3, 4) then 1 else 0 end
+ case when t17.a in (2, 3, 4) then 1 else 0 end
+ case when t18.a in (2, 3, 4) then 1 else 0 end
+ case when t19.a in (2, 3, 4) then 1 else 0 end
+ case when t20.a in (2, 3, 4) then 1 else 0 end) in (1, 4)
) 
 or (t1.a = 4 and (case when t1.a in (2, 3, 4) then 1 else 0 end
+ case when t2.a in (2, 3, 4) then 1 else 0 end
+ case when t3.a in (2, 3, 4) then 1 else 0 end
+ case when t4.a in (2, 3, 4) then 1 else 0 end
+ case when t5.a in (2, 3, 4) then 1 else 0 end
+ case when t6.a in (2, 3, 4) then 1 else 0 end
+ case when t7.a in (2, 3, 4) then 1 else 0 end
+ case when t8.a in (2, 3, 4) then 1 else 0 end
+ case when t9.a in (2, 3, 4) then 1 else 0 end
+ case when t10.a in (2, 3, 4) then 1 else 0 end
+ case when t11.a in (2, 3, 4) then 1 else 0 end
+ case when t12.a in (2, 3, 4) then 1 else 0 end
+ case when t13.a in (2, 3, 4) then 1 else 0 end
+ case when t14.a in (2, 3, 4) then 1 else 0 end
+ case when t15.a in (2, 3, 4) then 1 else 0 end
+ case when t16.a in (2, 3, 4) then 1 else 0 end
+ case when t17.a in (2, 3, 4) then 1 else 0 end
+ case when t18.a in (2, 3, 4) then 1 else 0 end
+ case when t19.a in (2, 3, 4) then 1 else 0 end
+ case when t20.a in (2, 3, 4) then 1 else 0 end)  in (2, 3, 5)
)
or (t1.a = 5 and (case when t1.a in (2, 3, 4) then 1 else 0 end
+ case when t2.a in (2, 3, 4) then 1 else 0 end
+ case when t3.a in (2, 3, 4) then 1 else 0 end
+ case when t4.a in (2, 3, 4) then 1 else 0 end
+ case when t5.a in (2, 3, 4) then 1 else 0 end
+ case when t6.a in (2, 3, 4) then 1 else 0 end
+ case when t7.a in (2, 3, 4) then 1 else 0 end
+ case when t8.a in (2, 3, 4) then 1 else 0 end
+ case when t9.a in (2, 3, 4) then 1 else 0 end
+ case when t10.a in (2, 3, 4) then 1 else 0 end
+ case when t11.a in (2, 3, 4) then 1 else 0 end
+ case when t12.a in (2, 3, 4) then 1 else 0 end
+ case when t13.a in (2, 3, 4) then 1 else 0 end
+ case when t14.a in (2, 3, 4) then 1 else 0 end
+ case when t15.a in (2, 3, 4) then 1 else 0 end
+ case when t16.a in (2, 3, 4) then 1 else 0 end
+ case when t17.a in (2, 3, 4) then 1 else 0 end
+ case when t18.a in (2, 3, 4) then 1 else 0 end
+ case when t19.a in (2, 3, 4) then 1 else 0 end
+ case when t20.a in (2, 3, 4) then 1 else 0 end) = 5
) 
) /* 12 */
and
(
t1.a != 1 and t3.a != 1  and t5.a != 1  and t7.a != 1 and t19.a != 1 and 
 (
     t13.a = 1 and (t9.a = 1  and t11.a != 1  and t13.a != 1 and t15.a != 1 and t17.a != 1 and t19.a != 1)
  or t13.a = 2 and (t9.a != 1  and t11.a = 1  and t13.a != 1 and t15.a != 1 and t17.a != 1 and t19.a != 1)
  or t13.a = 3 and (t9.a != 1  and t11.a != 1  and t13.a = 1 and t15.a != 1 and t17.a != 1 and t19.a != 1)
  or t13.a = 4 and (t9.a != 1  and t11.a != 1  and t13.a != 1 and t15.a = 1 and t17.a != 1 and t19.a != 1)
  or t13.a = 5 and (t9.a != 1  and t11.a != 1  and t13.a != 1 and t15.a != 1 and t17.a = 1 )
)
) /* 13 */
and
(
t14.a = (case when t1.a = 4 then 1 else 0 end
+ case when t2.a = 4 then 1 else 0 end
+ case when t3.a = 4 then 1 else 0 end
+ case when t4.a = 4 then 1 else 0 end
+ case when t5.a = 4 then 1 else 0 end
+ case when t6.a = 4 then 1 else 0 end
+ case when t7.a = 4 then 1 else 0 end
+ case when t8.a = 4 then 1 else 0 end
+ case when t9.a = 4 then 1 else 0 end
+ case when t10.a = 4 then 1 else 0 end
+ case when t11.a = 4 then 1 else 0 end
+ case when t12.a = 4 then 1 else 0 end
+ case when t13.a = 4 then 1 else 0 end
+ case when t14.a = 4 then 1 else 0 end
+ case when t15.a = 4 then 1 else 0 end
+ case when t16.a = 4 then 1 else 0 end
+ case when t17.a = 4 then 1 else 0 end
+ case when t18.a = 4 then 1 else 0 end
+ case when t19.a = 4 then 1 else 0 end
+ case when t20.a = 4 then 1 else 0 end) - 5
) /* 14 */
and
(
t15.a = t12.a
) /* 15 */
and
(
    (t16.a = 1 and t10.a = 4)
or (t16.a = 2 and t10.a = 3)
or (t16.a = 3 and t10.a = 2)
or (t16.a = 4 and t10.a = 1)
or (t16.a = 5 and t10.a = 5)
) /* 16 */
and
(
   (t17.a = 1 and t6.a = 3)
or (t17.a = 2 and t6.a = 4)
or (t17.a = 3 and t6.a = 5)
or (t17.a = 4 and not t6.a in (3, 4, 5)) 
) /* 17 */
 
and
(
(t18.a = 1 and
((case when t1.a = 1 then 1 else 0 end
+ case when t2.a = 1 then 1 else 0 end
+ case when t3.a = 1 then 1 else 0 end
+ case when t4.a = 1 then 1 else 0 end
+ case when t5.a = 1 then 1 else 0 end
+ case when t6.a = 1 then 1 else 0 end
+ case when t7.a = 1 then 1 else 0 end
+ case when t8.a = 1 then 1 else 0 end
+ case when t9.a = 1 then 1 else 0 end
+ case when t10.a = 1 then 1 else 0 end
+ case when t11.a = 1 then 1 else 0 end
+ case when t12.a = 1 then 1 else 0 end
+ case when t13.a = 1 then 1 else 0 end
+ case when t14.a = 1 then 1 else 0 end
+ case when t15.a = 1 then 1 else 0 end
+ case when t16.a = 1 then 1 else 0 end
+ case when t17.a = 1 then 1 else 0 end
+ case when t18.a = 1 then 1 else 0 end
+ case when t19.a = 1 then 1 else 0 end
+ case when t20.a = 1 then 1 else 0 end) = 
 (case when t1.a = 2 then 1 else 0 end
+ case when t2.a = 2 then 1 else 0 end
+ case when t3.a = 2 then 1 else 0 end
+ case when t4.a = 2 then 1 else 0 end
+ case when t5.a = 2 then 1 else 0 end
+ case when t6.a = 2 then 1 else 0 end
+ case when t7.a = 2 then 1 else 0 end
+ case when t8.a = 2 then 1 else 0 end
+ case when t9.a = 2 then 1 else 0 end
+ case when t10.a = 2 then 1 else 0 end
+ case when t11.a = 2 then 1 else 0 end
+ case when t12.a = 2 then 1 else 0 end
+ case when t13.a = 2 then 1 else 0 end
+ case when t14.a = 2 then 1 else 0 end
+ case when t15.a = 2 then 1 else 0 end
+ case when t16.a = 2 then 1 else 0 end
+ case when t17.a = 2 then 1 else 0 end
+ case when t18.a = 2 then 1 else 0 end
+ case when t19.a = 2 then 1 else 0 end
+ case when t20.a = 2 then 1 else 0 end)))
or (t18.a = 2 and
((case when t1.a = 1 then 1 else 0 end
+ case when t2.a = 1 then 1 else 0 end
+ case when t3.a = 1 then 1 else 0 end
+ case when t4.a = 1 then 1 else 0 end
+ case when t5.a = 1 then 1 else 0 end
+ case when t6.a = 1 then 1 else 0 end
+ case when t7.a = 1 then 1 else 0 end
+ case when t8.a = 1 then 1 else 0 end
+ case when t9.a = 1 then 1 else 0 end
+ case when t10.a = 1 then 1 else 0 end
+ case when t11.a = 1 then 1 else 0 end
+ case when t12.a = 1 then 1 else 0 end
+ case when t13.a = 1 then 1 else 0 end
+ case when t14.a = 1 then 1 else 0 end
+ case when t15.a = 1 then 1 else 0 end
+ case when t16.a = 1 then 1 else 0 end
+ case when t17.a = 1 then 1 else 0 end
+ case when t18.a = 1 then 1 else 0 end
+ case when t19.a = 1 then 1 else 0 end
+ case when t20.a = 1 then 1 else 0 end) = 
 (case when t1.a = 3 then 1 else 0 end
+ case when t2.a = 3 then 1 else 0 end
+ case when t3.a = 3 then 1 else 0 end
+ case when t4.a = 3 then 1 else 0 end
+ case when t5.a = 3 then 1 else 0 end
+ case when t6.a = 3 then 1 else 0 end
+ case when t7.a = 3 then 1 else 0 end
+ case when t8.a = 3 then 1 else 0 end
+ case when t9.a = 3 then 1 else 0 end
+ case when t10.a = 3 then 1 else 0 end
+ case when t11.a = 3 then 1 else 0 end
+ case when t12.a = 3 then 1 else 0 end
+ case when t13.a = 3 then 1 else 0 end
+ case when t14.a = 3 then 1 else 0 end
+ case when t15.a = 3 then 1 else 0 end
+ case when t16.a = 3 then 1 else 0 end
+ case when t17.a = 3 then 1 else 0 end
+ case when t18.a = 3 then 1 else 0 end
+ case when t19.a = 3 then 1 else 0 end
+ case when t20.a = 3 then 1 else 0 end)))
or (t18.a = 3 and
((case when t1.a = 1 then 1 else 0 end
+ case when t2.a = 1 then 1 else 0 end
+ case when t3.a = 1 then 1 else 0 end
+ case when t4.a = 1 then 1 else 0 end
+ case when t5.a = 1 then 1 else 0 end
+ case when t6.a = 1 then 1 else 0 end
+ case when t7.a = 1 then 1 else 0 end
+ case when t8.a = 1 then 1 else 0 end
+ case when t9.a = 1 then 1 else 0 end
+ case when t10.a = 1 then 1 else 0 end
+ case when t11.a = 1 then 1 else 0 end
+ case when t12.a = 1 then 1 else 0 end
+ case when t13.a = 1 then 1 else 0 end
+ case when t14.a = 1 then 1 else 0 end
+ case when t15.a = 1 then 1 else 0 end
+ case when t16.a = 1 then 1 else 0 end
+ case when t17.a = 1 then 1 else 0 end
+ case when t18.a = 1 then 1 else 0 end
+ case when t19.a = 1 then 1 else 0 end
+ case when t20.a = 1 then 1 else 0 end) = 
 (case when t1.a = 4 then 1 else 0 end
+ case when t2.a = 4 then 1 else 0 end
+ case when t3.a = 4 then 1 else 0 end
+ case when t4.a = 4 then 1 else 0 end
+ case when t5.a = 4 then 1 else 0 end
+ case when t6.a = 4 then 1 else 0 end
+ case when t7.a = 4 then 1 else 0 end
+ case when t8.a = 4 then 1 else 0 end
+ case when t9.a = 4 then 1 else 0 end
+ case when t10.a = 4 then 1 else 0 end
+ case when t11.a = 4 then 1 else 0 end
+ case when t12.a = 4 then 1 else 0 end
+ case when t13.a = 4 then 1 else 0 end
+ case when t14.a = 4 then 1 else 0 end
+ case when t15.a = 4 then 1 else 0 end
+ case when t16.a = 4 then 1 else 0 end
+ case when t17.a = 4 then 1 else 0 end
+ case when t18.a = 4 then 1 else 0 end
+ case when t19.a = 4 then 1 else 0 end
+ case when t20.a = 4 then 1 else 0 end)))
or (t18.a = 4 and
((case when t1.a = 1 then 1 else 0 end
+ case when t2.a = 1 then 1 else 0 end
+ case when t3.a = 1 then 1 else 0 end
+ case when t4.a = 1 then 1 else 0 end
+ case when t5.a = 1 then 1 else 0 end
+ case when t6.a = 1 then 1 else 0 end
+ case when t7.a = 1 then 1 else 0 end
+ case when t8.a = 1 then 1 else 0 end
+ case when t9.a = 1 then 1 else 0 end
+ case when t10.a = 1 then 1 else 0 end
+ case when t11.a = 1 then 1 else 0 end
+ case when t12.a = 1 then 1 else 0 end
+ case when t13.a = 1 then 1 else 0 end
+ case when t14.a = 1 then 1 else 0 end
+ case when t15.a = 1 then 1 else 0 end
+ case when t16.a = 1 then 1 else 0 end
+ case when t17.a = 1 then 1 else 0 end
+ case when t18.a = 1 then 1 else 0 end
+ case when t19.a = 1 then 1 else 0 end
+ case when t20.a = 1 then 1 else 0 end) = 
 (case when t1.a = 5 then 1 else 0 end
+ case when t2.a = 5 then 1 else 0 end
+ case when t3.a = 5 then 1 else 0 end
+ case when t4.a = 5 then 1 else 0 end
+ case when t5.a = 5 then 1 else 0 end
+ case when t6.a = 5 then 1 else 0 end
+ case when t7.a = 5 then 1 else 0 end
+ case when t8.a = 5 then 1 else 0 end
+ case when t9.a = 5 then 1 else 0 end
+ case when t10.a = 5 then 1 else 0 end
+ case when t11.a = 5 then 1 else 0 end
+ case when t12.a = 5 then 1 else 0 end
+ case when t13.a = 5 then 1 else 0 end
+ case when t14.a = 5 then 1 else 0 end
+ case when t15.a = 5 then 1 else 0 end
+ case when t16.a = 5 then 1 else 0 end
+ case when t17.a = 5 then 1 else 0 end
+ case when t18.a = 5 then 1 else 0 end
+ case when t19.a = 5 then 1 else 0 end
+ case when t20.a = 5 then 1 else 0 end)))
) /* 18 */
</pre>
<p>Как ни странно это всё довольно быстро написалось, довольно быстро отладилось и в результате дало ответ. Причём, запрос на моей машине отрабатывал за 4 секунды(!!!), что меня очень удивило и заставило уважать оптимизатор MS SQL Server&rsquo;а. Всё-таки в блоке FROM стоит декартово произведение, дающее 5^19 = 1.90734863 × 10<sup>13</sup> элементов, полный перебор выполнялся бы нереально долго.</p>]]></content:encoded></item><item><title>LINQ для строк</title><link>https://konstantin.gladyou.click/posts/2011-03-31-linq/</link><pubDate>Thu, 31 Mar 2011 04:55:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2011-03-31-linq/</guid><description>&lt;p>Недавно проводил на работе мини-олимпиаду по программированию. Включил одну задачу на LINQ, так как эта технология уже в каждом проекте так и лезет.&lt;/p></description><content:encoded><![CDATA[<p>Недавно проводил на работе мини-олимпиаду по программированию. Включил одну задачу на LINQ, так как эта технология уже в каждом проекте так и лезет.</p>
<p>Задача звучит так:</p>
<p>Имеется длинная строка символов. Необходимо одним выражением
LINQ получить набор
строк, представляющих собой разбиение исходной строки на подстроки с одинаковым
числом символов (тип результата 
<span style="font-family:&quot;Courier New&quot;;color:#2B91AF;">IEnumerable</span><span style="font-family:&quot;Courier New&quot;">&lt;<span style="color:blue">string</span></span>&gt;). </p>
<table border="1">
<tr>
<td>Исходная строка</td>
<td>Результат</td>
</tr>
<tr>
<td width="100px"><pre>Разбить на строки ABCDEFGHIJKLMNOPQRSTUVWXYZZZZZZZZ.</pre></td>
<td width="100px"><pre>Разбить на с<br>
троки ABCDEF<br>
GHIJKLMNOPQR<br>
STUVWXYZZZZZ<br>
ZZZ.</pre>
</td>
</tr>
</table>
Допустимо использовать любые стандартные фукнции, дополнительные
переменные, анонимные типы и лямбда-выражения, синтаксис запросов LINQ либо
методов расширений. Недопустимо использовать в запросе операторы цикла.
<p>Один из наиболее &ldquo;навороченных&rdquo; вариантов решения:</p>
<pre style="font-family:&quot;Courier New&quot;">
<span style="color:blue;">var</span> res =
    str.Select((c, i) =>
       					<span style="color:green;">// Разбиваем строку на символы с номерами</span>
        <span style="color:blue;">new</span>
        {
            Value = c,              <span style="color:green;">// Символ</span>
            Index = i,              <span style="color:green;">// Позиция символа в изначальной строке</span>
            LineNumber = i / width  <span style="color:green;">// Номер строки</span>
        }
    )
.GroupBy(g => g.LineNumber, e => e) <span style="color:green;">// Объединяем символы одной строки</span>
.Select(ar => ar.Select(ars => ars.Value))
.Select(outs => <span style="color:blue;">new string</span>(outs.ToArray())); <span style="color:green;">// Склеиваем символы обратно в строки</span>
</pre>
<p>Это наиболее &ldquo;чистый&rdquo; LINQ-запрос, не использующий никаких дополнительных
средств, кроме создания строк из массива символов. Используется вариант
метода Select(), позволяющий работать с индексом элемента во входной
последовательности.</p>
<p>Другой вариант жюри предполагал использование метода  <span style="font-family:&quot;Courier New&quot;;color:#2B91AF;">Enumerable</span><span style="font-family:&quot;Courier New&quot;">.Range()</span>
как замену цикла. Здесь основная идея в том, что мы можем заранее
определить, сколько строк получится в результате, а по номеру символа в
строке узнать, к какой строке он относится:</p>
<pre style="font-family:&quot;Courier New&quot;">
<span style="color:blue;">var</span> res = Enumerable
.Range(0, str.Length / width + 1) <span style="color:green;">// Массив номеров будущих строк</span>
.Join(
    str.ToCharArray().Select((c, i) =>
    {  <span style="color:green;">// Разбиваем строку на символы с номерами</span>
        <span style="color:blue;">return new</span> { Value = c, Index = i };
    }),
    s => s,
    d => d.Index / width, <span style="color:green;">// По номеру символа определяем, к какой строке он будет относится</span>
    (s, d) => <span style="color:blue;">new</span> { s, d })
.GroupBy(g => g.s, e => e) <span style="color:green;">// Объединяем символы одной строки</span>
.Select(ar => ar.Select(ars => ars.d.Value))
.Select(outs => <span style="color:blue;">new string</span>(outs.ToArray())); <span style="color:green;">// Склеиваем символы обратно в строки</span>
</pre>
<p>Это решение можно упростить до примитивного  (но тем не менее корректного):</p>
<pre style="font-family:&quot;Courier New&quot;">
<span style="color:blue;">var</span> res = <span style="font-family:&quot;Courier New&quot;;color:#2B91AF;">Enumerable</span>
.Range(0, str.Length / width + 1) <span style="color:green;">// Массив номеров будущих строк</span>
.Select(s => str.Substring(s * width, <span style="font-family:&quot;Courier New&quot;;color:#2B91AF;">Math</span>.Min(width, str.Length - s * width))); <span style="color:green;">// Выберем подстроки</span>
</pre>]]></content:encoded></item><item><title>Планирование ошибок в разработке</title><link>https://konstantin.gladyou.click/posts/2010-11-15-post-2925/</link><pubDate>Mon, 15 Nov 2010 00:07:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2010-11-15-post-2925/</guid><description>&lt;p>Двенадцатого ноября прошла очередная встреча &lt;a href="http://eastdev.blogspot.com/2010/11/developers-ug-omsk-12.html">Developers UG-Omsk&lt;/a>. Для меня эта встреча была знаменательна тем, что на ней я читал доклад. Ораторское искусство еще есть, куда совершенствовать, но в целом прошло неплохо. :) Выкладываю текст доклада здесь:&lt;/p></description><content:encoded><![CDATA[<p>Двенадцатого ноября прошла очередная встреча <a href="http://eastdev.blogspot.com/2010/11/developers-ug-omsk-12.html">Developers UG-Omsk</a>. Для меня эта встреча была знаменательна тем, что на ней я читал доклад. Ораторское искусство еще есть, куда совершенствовать, но в целом прошло неплохо. :) Выкладываю текст доклада здесь:</p>
<p>Добрый день. Сегодня мне хочется поговорить не о замечательно красивых  теоретических аспектах разработки ПО, не о технологиях и языках, а о сугубо практических вещах, с которыми мне приходится сталкиваться постоянно.</p>
<p>Давайте поговорим об ошибках. О процессе программирования говорят часто, разрабатываются технологии программирования,  шаблоны проектирования, проводятся разнообразные курсы. Об ошибках говорят редко и, обычно замечают только две вещи: 1) Ошибки есть всегда; 2) Надо стремиться к тому, чтоб ошибок не было.</p>
<p>На мой взгляд, с точки зрения ошибок на разработку смотрят недостаточно часто, хотя на практике заниматься отладкой и исправлением ошибок приходится чаще, чем собственно реализацией новой функциональности.</p>
<p>Ошибки, обычно недооцениваются. Но недооценка не может длиться долго, рано или поздно случается что-то такое, что показывает всю важность ошибок. Обычно это что-то выглядит как-то вот так: <center><br><img src="https://konstantin.gladyou.click/konstantin/bukov_net_pic_000093ck.jpg"><br></center></p>
<p>Программист может увидеть такую ошибку с утра в пятницу  с припиской от менеджера, что рухнул сданный в эксплуацию программный комплекс,  развернутый где-нибудь в США или Китае, и от заказчика пришёл только вот этот скриншот ошибки. И что ошибку надо срочно, в течение часа, максимум дня,  исправить.</p>
<p>Если программисту по такой информации не удастся исправить ошибку  (а это наверняка), то он может попрощаться с выходными. А если все логирование ошибок находится на таком же уровне, то можно попрощаться и с карьерой.</p>
<p>Программист, хотя бы один раз побывавший в такой ситуации, начинает во всех  своих приложениях писать перехватчики исключений и выдает уже гораздо более  информативные окна. Например, такие: <center><br><img src="https://konstantin.gladyou.click/konstantin/bukov_net_pic_00008qz7.jpg"><br></center></p>
<p>Так же некрасиво, но гораздо информативней. С таким скриншотом уже можно  попробоват что-нибудь починить. Кстати, насчет красоты экрана об ошибке также  стоит подумать. В моей практике был случай, когда заказчик перестал требовать исправление обрушения программы, после  того, как мы сделали нормальный экран ошибки. :) То есть пользователи очень пугались стандартного сообщения о закрытии программы и рапортовали начальству: &ldquo;Программа поломалась! Все пропало!&rdquo; Сделали красивое окно с сообщением: &ldquo;В результате расчета возникла ошибка. Программа будет перезагружена.&rdquo; Пользователи видели, что все идет, как надо и начальство не беспокоили. :)</p>
<p>Особо следует отметить очень опасный подход к сообщениям об ошибках, который встречается не только у новичков, но и, изредка, у опытных разработчиков. Этот подход заключается в том, что вообще никакие сообщения об ошибке не  выдаются, а все исключения молча проглатываются. Такое приложение в случае  возникновения ошибок выглядит очень странно: перестают работать какие-то кнопки, отключаются пункты меню, появляются пустые окошки без содержимого.  И пользователь недоволен, и исправлять это сложно.</p>
<p>Тем не менее, перехват исключений с выводом информативных сообщений &ndash; не панацея. Таким образом можно получить только сиюминутную информацию. То есть мы можем увидеть, что в работающей программе оказалась непроинициализированной какая-то переменная. Почему это случилось, обычно остается загадкой. Поэтому надо активно применять систему логирования. С помощью логирования можно получить описание цепочки событий, которые привели к сбою.</p>
<p>Для логирования есть разные готовые компоненты. Эта тема вообще довольно хорошо проработана, поэтому останавливаться на логировании мы не будем.</p>
<p>Поговорим лучше о юнит-тестировании. Все, что я говорил раньше, касалось ошибок, которые возникали внезапно, в процессе эксплуатации ПО. Юнит-тесты же позволяют автоматически проходить по критическим кускам кода и проверять ошибки.</p>
<p>Успешный прогон unit-тестов выглядит примерно так: <center><br><img src="https://konstantin.gladyou.click/konstantin/bukov_net_pic_0000cc77.jpg"><br></center></p>
<p>Все протестировано, все в порядке. Если в результате модификации кода,  нарушается логика работы приложения, то хорошие unit-тесты проведут регрессионное тестирование и покажут ошибку: <center><br><img src="https://konstantin.gladyou.click/konstantin/bukov_net_pic_0000a3pe.jpg"><br></center> Unit-тест локализует ошибку и сразу показывает, что надо исправлять. Ну&hellip; В идеальном случае. К сожалению, на практике ошибка unit-тестов выглядит обычно примерно так: <center><br><img src="https://konstantin.gladyou.click/konstantin/bukov_net_pic_0000be34.jpg"><br></center> То есть некоторые ошибки ломают все unit-тесты или большую их часть.  О чем это свидетельствует? Это свидетельствует о слишком тесно связанных блоках, неаккуратном дизайне. Например, в одном из моих проектов было отдельное  вычислительное ядро, которое несло на себе расчетную часть бизнес-логики. Часто любая ошибка в этом ядре ломала все unit-тесты ядра. А был еще отдельный модуль конфигурации, любая ошибка в котором ломала вообще все unit-тесты.</p>
<p>Сами по себе unit-тесты, конечно, никого особо не волнуют, но сильная  связанность разных частей системы влечет за собой увеличение стоимости поддержки. На практике был случай. Два разработчика занимались разными частями программы. Один из них исправил какой-то не особо сложный дефект. После следующей сборки вылез новый дефект у другого разработчика. Тот исправил его &ndash; и снова вылез баг у первого разработчика. В результате эта пара дефектов была исправлена 4 раза, до тех пор пока не пришел тестировщик, не собрал этих разработчиков и не показал  им,  что это связанные дефекты. Сами разработчики эту связь отследить не могли, так как система сложная, а в коде эти дефекты каждый раз выглядели слегка  по-разному. В результате вместо быстрого исправления одиночной ошибки получилась долгая эпопея, вовлекающая сразу несколько человек.</p>
<p>Отдельным случаем идет невозможность написания unit-тестов. Такое бывает,  например, когда бизнес-логика тесно переплена с логикой отображения. Или когда бизнес-логика равномерно размазана между визуальными формами, базой данных и различными классами.</p>
<p>То есть, когда вы имеете проблемы с unit-тестами, то скорее всего у вас более  глубокие проблемы с ошибками, которые, возможно, потребуют какой-то переделки кода. Кстати, если у вас нет unit-тестов, это не значит, что и проблем нет. Проблемы есть, только о них неизвестно.</p>
<p>Для устранения излишней связности системы производят разбиение по модулям, Layering, Dependepcy Injection и прочее.</p>
<p>Простота отладки и исправления ошибок должна быть на одном из первых мест в проектировании приложения. Расскажу еще одну историю: о программе, отладка которой становилась невозможна, если в отладчике мышкой перекрестить код.</p>
<center><br><img src="https://konstantin.gladyou.click/konstantin/bukov_net_pic_00007cd7.jpg"><br></center> <center><br><img src="https://konstantin.gladyou.click/konstantin/bukov_net_pic_0000dk5q.jpg"><br></center>
<p>Основная часть программы представляла собой грид с числовыми значениями. В гриде были итоговые ячейки для строк, столбцов, просто групп значений, были неявные связи через различные коэффициенты. В общем в результате любая ячейка зависила от любой другой ячейки. Причем связи эти были очень сложные. В результате любое изменение в любой ячейке затрагивало абсолютно все другие ячейки.</p>
<p>Чтоб значения ячеек всегда были в актуальном состоянии, любое обращение к свойству Value объекта-ячейки вызывало пересчет всех связанных ячеек. Очень сложная логика взаимодействия объектов, которая на практике себя показала гораздо хуже, чем в теории.</p>
<p>В частности эту систему оказалось практически невозможно отлаживать. Основная проблема внешне появлялась именно в том, о чем я уже говорил: достаточно было в отладке перекрестить исходный код программы, чтобы результаты отладки были абсолютно другими, чем при обычной работе программы. На скриншоте хорошо видно, почему так происходило. Как только мышка проходит над свойством Value, Visual Studio пытается получить значение свойства. Так как в геттере объекта вызывается принудительный пересчет всех зависимых объектов, то достаточно один раз провести мышкой над свойством, чтобы изменить всю логику расчетов. В окно Watches также нельзя было добавлять экземпляры этих объектов по тем же причинам.</p>
<p>В результате исправление любой ошибки с расчетами выливалось в двух-трехдневную глубокую отладку. Помучившись несколько месяцев, переписали эту часть системы.</p>
<p>На сегодня это все истории про ошибки, которые я хотел рассказать. Без  серьезного структурированного подхода мы мельком пробежались по тому, какое  влияние оказывают ошибки на интерфейс, на сервисы, реализуемые в ПО, на архитектуру и дизайн, а также на непосредственное низкоуровневое  взаимодействие объектов.</p>
<p>В общем-то, никаких глубоких целей этот доклад не преследовал. Просто мне  хочется обратить внимание на еще одну грань разработки ПО. И хочется, чтобы прежде, чем все мы до внедрения какой-то технологии, продукта или решения,  подумали бы, а удобно ли нам будет в этой новой среде делать ошибки и исправлять  их.</p>]]></content:encoded></item><item><title>Конференция была!</title><link>https://konstantin.gladyou.click/posts/2010-10-24-post-2780/</link><pubDate>Sun, 24 Oct 2010 14:26:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2010-10-24-post-2780/</guid><description>&lt;p>Я уже &lt;a href="https://konstantin.gladyou.click/posts/2010-10-02-expert-labs-2010/">писал&lt;/a>, что в Омске намечается конференция Expert Labs 2010. Так вот я на ней таки побывал, чему несказанно рад.&lt;/p></description><content:encoded><![CDATA[<p>Я уже <a href="https://konstantin.gladyou.click/posts/2010-10-02-expert-labs-2010/">писал</a>, что в Омске намечается конференция Expert Labs 2010. Так вот я на ней таки побывал, чему несказанно рад.</p>
<p>Началась конференция очень правильно, с утреннего кофе:
<img src="https://konstantin.gladyou.click/konstantin/bukov_net_pic_000017zf.jpg"/><br>
Столы с закусками еще выставлялись в обед и на них даже оставалась еда после того, как все наедались, что для конференций не типично. :) То ли бутербродов было выше среднего, то ли разговоры застольные были настолько интересны, что многие забывали о еде. А на самом деле и то, и то.</p>
<p>Народа было солидно, человек семьдесят, наверное. В принципе, не удивительно, так как эта конференция была действительно первым таким масштабным мероприятием в Омске. Меня удивило, что приехала целая группа людей из Новосибирска. Судя по всему в Новосибирске IT-жизнь кипит.
<img src="https://konstantin.gladyou.click/konstantin/bukov_net_pic_000023zf.jpg"/><br></p>
<p>В отведенное для докладов короткое время докладчики часто не укладывались и обуждение продолжалось и в перерыве. Именно в перерывах мне удалось узнать, как заказчику выдается оценка в баклоге для связанных задач, и зачем аналитикам требуется знание SQL:
<img src="https://konstantin.gladyou.click/konstantin/bukov_net_pic_000039qd.jpg"/><br></p>
<p>Наиболее интересными были, конечно, пленарные доклады Александра Орлова и Асхата Уразбаева. Но лично меня также очень порадовал омский доклад Антона Непомнящих (ИСС Арт). Фактически в докладе были показано, как то, о чем говорят мэтры, выглядит на практике. В целом правильные слова о visibility и buisiness value гораздо лучше воспринимаются, когда послушаешь, что заказчик снял разработчика, долгое время &ldquo;допиливавшего&rdquo; ядро системы:
<img src="https://konstantin.gladyou.click/konstantin/bukov_net_pic_00005w19.jpg"/><br></p>
<p>После официальной части примерно половина всех участников двинула в ресторан &ldquo;Сибирская корона&rdquo;. Там возникла очень забавная ситуация: был заказан столик на 15 человек, а пришло около 30. Менеджер зала сказала, что такое количество людей разместить у нее абсолютно никак не получится, так как все столики уже заказаны. Тут я испытал гордость за IT-индустрию Сибири. С менеджером никто не спорил, сразу признали ее правоту, но все люди начали одновременно предпринимать действия по перемещению в другой ресторан: те, кто начали что-то заказывать, заказы отменяли, часть людей через смартфоны искала телефоны соседних больших ресторанов, другая часть по этим телефонам начала звонить и договариваться о помещении. И все это без команд какого-то выделенного руководителя. Самоорганизация в действии. В общем, буквально через секунд 30 после того, как нам сказали, что мест нет, места нашлись. :)
<img src="https://konstantin.gladyou.click/konstantin/bukov_net_pic_00006dat.jpg"/><br></p>
<p>Такое afterparty, по-моему, настолько же ценно, как и официальная часть. Мне, например, удалось поговорить о бизнесе с директором небольшой оутсорсинговой компании, с руководителем проектов, который одновременно ведет 30 проектов, с менеджером, который использует совместные еженедельные пьянки как оргиназационный инструмент и еще со многими другими людьми. Удалось, например, узнать, почему были такие большие проблемы с недельными итерациями. То есть прямо таки очевидная полезность от мероприятия. Побольше бы таких!</p>]]></content:encoded></item><item><title>Рефлексы</title><link>https://konstantin.gladyou.click/posts/2010-10-23-post-2510/</link><pubDate>Sat, 23 Oct 2010 09:21:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2010-10-23-post-2510/</guid><description>У монитора стали изредка появляться местами какие-то дрожащие ореолы из разноцветных пикселей. Жена отвезла его в ремонт, причем на приемке мастер на эти ореолы поглядел и сказал, что проблема ясна, будут чинить. Через несколько дней в ремонте сказали, что монитор можно забирать назад, так как проблема у мастера за четыре дня не проявилась и, соответственно, делать никто ничего не будет.
Очень долго удивлялся на такой подход. В разработке невоспроизводимость бага абсолютно не означает, что его можно закрывать.</description><content:encoded>&lt;p>У монитора стали изредка появляться местами какие-то дрожащие ореолы из разноцветных пикселей. Жена отвезла его в ремонт, причем на приемке мастер на эти ореолы поглядел и сказал, что проблема ясна, будут чинить. Через несколько дней в ремонте сказали, что монитор можно забирать назад, так как проблема у мастера за четыре дня не проявилась и, соответственно, делать никто ничего не будет.&lt;/p>
&lt;p>Очень долго удивлялся на такой подход. В разработке невоспроизводимость бага абсолютно не означает, что его можно закрывать. Жаль, что в области бытовых услуг не так. :)&lt;/p></content:encoded></item><item><title>Конференция Expert Labs 2010</title><link>https://konstantin.gladyou.click/posts/2010-10-02-expert-labs-2010/</link><pubDate>Sat, 02 Oct 2010 14:45:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2010-10-02-expert-labs-2010/</guid><description>22 октября в Омске состоится конференция Expert Labs 2010, посвященная обучению в области разработки программного обеспечения. Программа конференции представлена на странице мероприятия.
Для Омска событие необычное, так как с IT-конференциями у нас как-то туговато. Темы докладов мне, разработчику, откровений не сулят, но для такой &amp;ldquo;неспециализированной&amp;rdquo; конференции — самое оно. Да и как раз можно будет на разных людей поглядеть. :)
В общем, очень хочется пойти, но смущает, что это надо будет с работы уйти на целый день.</description><content:encoded><![CDATA[<p>22 октября в Омске состоится конференция Expert Labs 2010, посвященная обучению в области разработки программного обеспечения. Программа конференции представлена на <a href="http://www.expert-labs.ru/program/">странице мероприятия</a>.</p>
<p>Для Омска событие необычное, так как с IT-конференциями у нас как-то туговато. Темы докладов мне, разработчику, откровений не сулят, но для такой &ldquo;неспециализированной&rdquo; конференции — самое оно. Да и как раз можно будет на разных людей поглядеть. :)</p>
<p>В общем, очень хочется пойти, но смущает, что это надо будет с работы уйти на целый день. Лучше бы в выходной провели.</p>
]]></content:encoded></item><item><title>Лицензионное ПО</title><link>https://konstantin.gladyou.click/posts/2010-09-21-post-1739/</link><pubDate>Tue, 21 Sep 2010 18:47:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2010-09-21-post-1739/</guid><description>Последнее время мне казалось, что пользоваться ворованными программами становится все сложнее и сложнее: ссылки на скачивание везде прибиваются, периодически кого-то судят и т.д. Даже винду себе купил, так оказалось проще.
Но тут понадобилось мне отпечаток визиток на 300 рублей. Прихожу в маленькую недорогую типографию и выясняется, что я могу на распечатку отдать макет либо в COrelDraw, либо в Adobe Photoshop, либо в MS Word 2007. На мой файлик в формате EPS сказали, что это Illustrator и что они с него печатать не могут (хотя открыть его открыли, у девочки на приемке, конечно, и Иллюстратор тоже стоит).</description><content:encoded><![CDATA[<p>Последнее время мне казалось, что пользоваться ворованными программами становится все сложнее и сложнее: ссылки на скачивание везде прибиваются, периодически кого-то судят и т.д. Даже винду себе купил, так оказалось проще.</p>
<p>Но тут понадобилось мне отпечаток визиток на 300 рублей. Прихожу в маленькую недорогую типографию и выясняется, что я могу на распечатку отдать макет либо в COrelDraw, либо в Adobe Photoshop, либо в MS Word 2007. На мой файлик в формате EPS сказали, что это Illustrator и что они с него печатать не могут (хотя открыть его открыли, у девочки на приемке, конечно, и Иллюстратор тоже стоит).</p>
<p>Покупать программу за тысячу баксов, чтобы отпечатать визиток на 300 рублей вряд ли кто-то будет. Есть еще, куда двигаться в плане борьбы с контрафактным ПО. :)</p>
]]></content:encoded></item><item><title>Lazy LINQ</title><link>https://konstantin.gladyou.click/posts/2010-09-15-lazy-linq/</link><pubDate>Wed, 15 Sep 2010 12:28:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2010-09-15-lazy-linq/</guid><description>&lt;p>Подивившись жизненной несправедливости в &lt;a href="https://konstantin.gladyou.click/posts/2010-09-12-linq/">прошлый раз&lt;/a>, я задумался, что прикрутить ленивую загрузку в LINQ запрос должно быть не очень-то и сложно.&lt;/p></description><content:encoded><![CDATA[<p>Подивившись жизненной несправедливости в <a href="https://konstantin.gladyou.click/posts/2010-09-12-linq/">прошлый раз</a>, я задумался, что прикрутить ленивую загрузку в LINQ запрос должно быть не очень-то и сложно.</p>
<p> Основная идея проста: сделать дополнительный метод расширения, который бы выдавал не сразу данные по <font style="font-family: consolas; color: blue;">yield return</font>, а возвращал бы какой-то объект, кеширующий после первого обращения данные.
Отложенность загрузки хотелось сохранить, грузить при первом обращении всю последовательность также не хотелось. Поэтому я создал <font style="font-family: consolas;"><font style="color: blue;">class</font>&nbsp;<font style="color: #2b91af">LazyEnumerable</font>&lt;T&gt;:&nbsp;<font style="color: #2b91af">IEnumerable</font>&lt;T&gt;</font>, в котором хранил исходную последовательность, объект-перечислитель для нее и уже загруженные данные в виде
обычного <font style="font-family: consolas"><font style="color: #2b91af">List</font>&lt;T&gt;</font>.
</p>
<p>
Вся логика была заключена в собственном объекте-перечислителе (enumerator) для этой последовательности. В конструктор энумератора я передавал исходную энумератор исходной последовательности и список уже загруженных элементов. Сперва я при обращении выдавал все элементы кеша, а когда они кончались, начинал выдавать элементы последовательности, заполняя попутно кеш:
</p>
<p>
    <pre style="font-family: consolas">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue">public</span>&nbsp;<span 
        style="color: blue">bool</span>&nbsp;MoveNext()
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue">if</span>&nbsp;(!_cacheEnded&nbsp;&amp;&amp;&nbsp;_cacheEnumerator.MoveNext())
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue">return</span>&nbsp;<span style="color: blue">true</span>;&nbsp;<span 
        style="color: green">//&nbsp;Идем&nbsp;по&nbsp;сохраненной&nbsp;последовательности</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue">else</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: green">//&nbsp;Сохраненная&nbsp;последовательность&nbsp;кончилась,&nbsp;идем&nbsp;по&nbsp;основноц</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_cacheEnded&nbsp;=&nbsp;<span style="color: blue">true</span>;&nbsp;<span 
        style="color: green">//&nbsp;Закончился&nbsp;кеш</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue">bool</span>&nbsp;res&nbsp;=&nbsp;_enumerator.MoveNext();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue">if</span>&nbsp;(res)&nbsp;_cache.Add(<span 
        style="color: blue">this</span>.Current);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue">return</span>&nbsp;res;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
<p>    <span style="color: blue">public</span> T Current
    {
        <span style="color: blue">get</span> 
        {
            <span style="color: blue">if</span> (!_cacheEnded) <span 
style="color: blue">return</span> _cacheEnumerator.Current;
            <span style="color: blue">else</span> <span style="color: blue">return</span> _enumerator.Current;</pre>
<pre style="font-family: consolas">         }</pre>
<pre style="font-family: consolas">}</pre></p>
</p>
<p>
При реализации в очередной раз порадовался, насколько шаблоны проектирования облегчают разработку. Идею можно сформулировать в понятной для любого разработчика формулировке: "Выдавать сперва энумератор сохраненной, а потом исходной последовательности." Хотя надо заметить, что получившийся код получился не супер-читаемым как минимум из-за того, что пришлось реализовывать и <font style="font-family: consolas"><font style="color: #2b91af">IEnumerator</font>&lt;T&gt;</font> и <font style="font-family: consolas"><font style="color: #2b91af">IEnumerator</font></font>. А это еще не добавлена потокобезопасность, например. Так что подобные методы массово писать без реальной необходимости я бы не стал.
</p>
<p>
Исходные коды для этого поста можно скачать <a href="http://katpop.narod.ru/files/jj/linqlazy.zip">отсюда</a>.
</p>]]></content:encoded></item><item><title>День программиста</title><link>https://konstantin.gladyou.click/posts/2010-09-14-post-1079/</link><pubDate>Tue, 14 Sep 2010 00:14:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2010-09-14-post-1079/</guid><description>&lt;p>Прочитал у Ибигдана &lt;a href="http://ibigdan.livejournal.com/7181219.html">поздравление&lt;/a> с днем программиста. Поздравление грустное и исполненное безнадеги профессионала ушедшего из профессии. Могу понять его грусть, но как ни странно с моей точки зрения в профессии программиста происходят вещи прямо обратные описанным.&lt;/p></description><content:encoded><![CDATA[<p>Прочитал у Ибигдана <a href="http://ibigdan.livejournal.com/7181219.html">поздравление</a> с днем программиста. Поздравление грустное и исполненное безнадеги профессионала ушедшего из профессии. Могу понять его грусть, но как ни странно с моей точки зрения в профессии программиста происходят вещи прямо обратные описанным.</p>
<p>Ибигдан пишет: &ldquo;Сегодня программист как волк флажками обставлен методологиями, готовыми решениями, тимбилдингом, промышленными стандартами, унаследованным кодом, шаблонами и прочим.&rdquo; А с моей точки зрения это не ограничения, а бесконечные подпорки для истинной творческой свободы. Раньше те же самые шаблоны проектирования использовались, только без формализации, интуитивно, часто незрело и недостаточно эффективно. Сейчас можно учиться, тренировать свой мозг, воплощать свои задумки в коде легче и быстрее прежнего.</p>
<p>Ибигдан пишет: &ldquo;только 10% работы программиста можно отнести к сколько-нибудь творческой.&rdquo; Ну да, конечно. Вот только даже я помню сам и знаю по рассказам программистов старшего поколения, как разработка еще не так давно сопровождалась сборкой компьютеров (вплоть до пайки отдельных блоков), сборкой и настройкой оргтехники, проводкой сети, обучением пользователей и бесконечным, нудным, однообразным созданием пользовательского интерфейса. А сейчас каждый волен заниматься тем, чем ему нравится и к чему есть способности. Вокруг меня сидят люди, у которых процент творческой работы уверенно приближается к ста процентам. И сам я создаю как раз эти самые виртуальные миры, которые становятся частью реальности.</p>
<p>Ибигдан пишет: &ldquo;И даже если у тебя есть идея, как решить уже сто раз решённую задачу новым, гениальным способом - кто даст тебе на это время и деньги? Как ты её потом будешь продвигать на рынке?&rdquo; Ну вот и вскрылось ядро проблемы. Творчество творчеством, а где же бабло?!! :) Как будто когда-то программистам деньги мешками выдавали, чтобы они решали &ldquo;уже сто раз решённую задачу&rdquo; пусть даже каким-то новым, &ldquo;гениальным&rdquo; способом.</p>
<p>Для реализации своих идей всегда приходится прилагать какие-то усилия, но именно сейчас стало проще воплотить свои идеи в коде за сравнительно небольшое время и распространить результат своей работы среди очень большого числа людей.</p>
<p>В общем, желаю всем программистам побольше интересных проектов, поменьше скучных багов, повыше зарплату и побольше креативных людей вокруг. С прадником, коллеги!</p>]]></content:encoded></item><item><title>Засада с LINQ</title><link>https://konstantin.gladyou.click/posts/2010-09-12-linq/</link><pubDate>Sun, 12 Sep 2010 22:02:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2010-09-12-linq/</guid><description>&lt;p>В процессе реализации программы, о которой я писал в прошлом &lt;a href="https://konstantin.gladyou.click/posts/2010-09-12-post-669/">посте&lt;/a>, я напоролся на одну забавную засаду.
&lt;br>&lt;br>&lt;/p></description><content:encoded><![CDATA[<p>В процессе реализации программы, о которой я писал в прошлом <a href="https://konstantin.gladyou.click/posts/2010-09-12-post-669/">посте</a>, я напоролся на одну забавную засаду.
<br><br></p>
<p>Дело в том, что слова из файла я получаю так (упрощенно):</p>
<div style="font-family: Courier New; font-size: 10pt; color: black; background: white;">
<p style="margin: 0px;"><span style="color: #2b91af;">&nbsp;&nbsp;&nbsp;24</span>&nbsp;<span style="color: blue;">while</span> (<span style="color: blue;">true</span>)</p>
<p style="margin: 0px;"><span style="color: #2b91af;">&nbsp;&nbsp;&nbsp;25</span>&nbsp;{</p>
<p style="margin: 0px;"><span style="color: #2b91af;">&nbsp;&nbsp;&nbsp;26</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span> word = file.ReadLine();</p>
<p style="margin: 0px;"><span style="color: #2b91af;">&nbsp;&nbsp;&nbsp;27</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: blue;">if</span> (word.Length == length) <span style="color: blue;">yield</span> <span style="color: blue;">return</span> word; <span style="color: green;">// &#1085;&#1072;&#1096;&#1083;&#1080; &#1089;&#1083;&#1086;&#1074;&#1086; &#1085;&#1091;&#1078;&#1085;&#1086;&#1081; &#1076;&#1083;&#1080;&#1085;&#1099;</span></p>
<p style="margin: 0px;"><span style="color: #2b91af;">&nbsp;&nbsp;&nbsp;28</span>&nbsp;}</p>
</div>
Никаких дополнительных телодвижений я не делал, так как неоднократно слышал, что в LINQ изначально реализован шаблон lazy load. Каково же было мое удивление, когда я потом увидел, что считывание файла идет <i>каждый раз</i> при получении значения из этого набора данных! Производительность просела так, что это было визуально заметно, я пожал плечами и, не разбираясь, прилепил один раз вызов .ToArray(), чтобы гарантировано считать слова, запомнить их и больше в файл не лазать.
<br><br>
Как оказалось, надо было сразу полезть вглубь отладки, чтобы разобраться, что к чему, так как аналогичная проблема вылезла очень скоро, но в гораздо более запутанном месте, при вот этом вызове:
<br><br>
<div style="font-family: Courier New; font-size: 10pt; color: black; background: white;">
<p style="margin: 0px;"><span style="color: #2b91af;">&nbsp;&nbsp;&nbsp;59</span>&nbsp;generation = generation.SelectMany(m =&gt; Step(m)); <span style="color: green;">// &#1055;&#1086;&#1083;&#1091;&#1095;&#1080;&#1084; &#1089;&#1083;&#1077;&#1076;&#1091;&#1102;&#1097;&#1077;&#1077; &#1087;&#1086;&#1082;&#1086;&#1083;&#1077;&#1085;&#1080;&#1077;</span></p>
</div>
<br>
Казалось бы обычное получение набора элементов следующего поколения. Но хотя эта команда давала правильные на первый взгляд результаты, любое следующее обращение к этим элементам выдавало пустое множество! То есть если вывести значение .Count() в консоль, то выдавалось число элементов, а если потом поглядеть результаты в отладке, то значений не было. Если выдать значение .Count() два раза в консоль, то во втором случае печатался 0!
<br><br>
Я впал в задумчивость, а потом в глубокую отладку. Благо рефлектор позволяет отладчиком трассировать внутренние вызовы стандартной библиотеки. Отладкой я быстро (часа через полтора) нашел корень зла: оказалось, что никакого lazy load в LINQ нет. Точнее есть lazy, а нет load. :) То есть данные не загружаются при создании LINQ-запроса, но даже когда требуются значения, никакого сохранения данных для ускорения последующего доступа не происходит! То есть мой метод .Step() (а ранее метод чтения из файла) вызывался каждый раз при обращении к набору. А это все ломало, так как внутри этого метода правились элементы колекции так, что повторно они не выбирались!
<br><br>
Так что я вписал второй вызов .ToArray() и получил работающую программу, а также бесценный опыт и философский взгляд на жизнь.]]></content:encoded></item><item><title>Делаем из мухи слона</title><link>https://konstantin.gladyou.click/posts/2010-09-12-post-669/</link><pubDate>Sun, 12 Sep 2010 17:24:00 +0000</pubDate><guid>https://konstantin.gladyou.click/posts/2010-09-12-post-669/</guid><description>&lt;p>Очень часто мне в голову приходят всякие дурацкие вопросы: &amp;ldquo;Сколько ангелов разместится на конце иглы?&amp;rdquo; или &amp;ldquo;Какова общая переплата по кредиту на 10 лет?&amp;rdquo; Ответы на некоторые из этих вопросов можно легко получить, написав совсем небольшую программку.
&lt;br>&lt;br>
Вот и недавно мне подумалось, что можно написать программу, которая будет решать старую задачку, делать из слова &amp;ldquo;муха&amp;rdquo; слово &amp;ldquo;слон&amp;rdquo;, меняя на каждом шаге не более одной буквы, так чтобы получалось новое слово. Например, из слона плед можно сделать довольно просто: слон-слот-плот-плод-плед. А вот из мухи слона сделать у меня без компьютера не получилось. Поэтому я решил написать программку, а заодно потренироваться в новой технологии LINQ. Исходный текст программы можно скачать &lt;a href="http://katpop.narod.ru//files/jj/elephantfly.zip">тут&lt;/a>.
&lt;br>&lt;br>&lt;/p></description><content:encoded><![CDATA[<p>Очень часто мне в голову приходят всякие дурацкие вопросы: &ldquo;Сколько ангелов разместится на конце иглы?&rdquo; или &ldquo;Какова общая переплата по кредиту на 10 лет?&rdquo; Ответы на некоторые из этих вопросов можно легко получить, написав совсем небольшую программку.
<br><br>
Вот и недавно мне подумалось, что можно написать программу, которая будет решать старую задачку, делать из слова &ldquo;муха&rdquo; слово &ldquo;слон&rdquo;, меняя на каждом шаге не более одной буквы, так чтобы получалось новое слово. Например, из слона плед можно сделать довольно просто: слон-слот-плот-плод-плед. А вот из мухи слона сделать у меня без компьютера не получилось. Поэтому я решил написать программку, а заодно потренироваться в новой технологии LINQ. Исходный текст программы можно скачать <a href="http://katpop.narod.ru//files/jj/elephantfly.zip">тут</a>.
<br><br></p>
<p>Общая идея была самая примитивная: от основного слова выбираем соседей, потом соседей соседей, потом соседей этих соседей и так, пока не найдется финальное слово. Все найденные слова-соседи маркируются указанием слова-родителя. В коде это выглядит очень просто:</p>
<div style="font-family: Courier New; font-size: 10pt; color: black; background: white;">
<p style="margin: 0px;"><span style="color: #2b91af;">&nbsp;&nbsp;&nbsp;43</span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">public</span> <span style="color: #2b91af;">IEnumerable</span>&lt;<span style="color: #2b91af;">WordItem</span>&gt; Step(<span style="color: #2b91af;">WordItem</span> item)</p>
<p style="margin: 0px;"><span style="color: #2b91af;">&nbsp;&nbsp;&nbsp;44</span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</p>
<p style="margin: 0px;"><span style="color: #2b91af;">&nbsp;&nbsp;&nbsp;45</span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">var</span> neighbours = items.Where(s =&gt; (s - item) == 1 <span style="color: green;">// &#1053;&#1072; &#1088;&#1072;&#1089;&#1089;&#1090;&#1086;&#1103;&#1085;&#1080;&#1080; 1</span></p>
<p style="margin: 0px;"><span style="color: #2b91af;">&nbsp;&nbsp;&nbsp;46</span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &amp;&amp;&nbsp; s.parent == <span style="color: blue;">null</span>).ToArray(); <span style="color: green;">// &#1048; &#1077;&#1097;&#1077; &#1085;&#1077; &#1087;&#1086;&#1089;&#1095;&#1080;&#1090;&#1072;&#1085;&#1099;</span></p>
<p style="margin: 0px;"><span style="color: #2b91af;">&nbsp;&nbsp;&nbsp;47</span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">foreach</span> (<span style="color: blue;">var</span> n <span style="color: blue;">in</span> neighbours) n.parent = item; <span style="color: green;">// &#1059;&#1089;&#1090;&#1072;&#1085;&#1086;&#1074;&#1080;&#1084; &#1088;&#1086;&#1076;&#1080;&#1090;&#1077;&#1083;&#1103;</span></p>
<p style="margin: 0px;"><span style="color: #2b91af;">&nbsp;&nbsp;&nbsp;48</span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">return</span> neighbours;</p>
<p style="margin: 0px;"><span style="color: #2b91af;">&nbsp;&nbsp;&nbsp;49</span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</p>
</div>
<br><br>
А после остается уже совсем тривиальная работа по итеративному вызову этой функции и поиску в результате нужного слова:
<br>
<div style="font-family: Courier New; font-size: 10pt; color: black; background: white;">
<p style="margin: 0px;"><span style="color: #2b91af;">&nbsp;&nbsp;&nbsp;59</span>&nbsp;generation = generation.SelectMany(m =&gt; Step(m)).ToArray(); <span style="color: green;">// &#1055;&#1086;&#1083;&#1091;&#1095;&#1080;&#1084; &#1089;&#1083;&#1077;&#1076;&#1091;&#1102;&#1097;&#1077;&#1077; &#1087;&#1086;&#1082;&#1086;&#1083;&#1077;&#1085;&#1080;&#1077;</span></p>
<p style="margin: 0px;"><span style="color: #2b91af;">&nbsp;&nbsp;&nbsp;60</span>&nbsp;<span style="color: blue;">var</span> endWord =&nbsp; generation.Where(w =&gt; w == secondWord).FirstOrDefault(); <span style="color: green;">// &#1055;&#1086;&#1080;&#1097;&#1077;&#1084;, &#1085;&#1077;&#1090; &#1083;&#1080; &#1092;&#1080;&#1085;&#1072;&#1083;&#1100;&#1085;&#1086;&#1075;&#1086; &#1089;&#1083;&#1086;&#1074;&#1072;</span></p>
</div>
<br><br>
Конечно, вокруг еще довольно много всякой возни с составлением набора четырехбуквенных слов (оказалось очень непросто найти нормальный словарь), поиском первого слова, выводом результирующей последовательности и т.д. Но все равно удивительно, что вообщем-то вся программа, благодаря LINQ, поместилась в четыре строчки! И вообще в программе много мест, которые LINQ позволяет записать просто удивительно компактно.
<br><br>
В реальных проектах, кстати, ситуация такая же: с появлением LINQ большие куски просто выкидываются и заменяются крошечными запросами. Не все так просто, к сожалению, но об этом лучше потом... Пусть первый пост журнала будет позитивным. :)
<p><br><br>
Ну и, конечно, напишу результат поисков. Цепочка получилась такая:
муха-мура-фура-фара-фарт-факт-пакт-паут-плут-плот-плод-плед-плен-клен-клон-слон</p>]]></content:encoded></item></channel></rss>