<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nizar</title>
    <description>The latest articles on DEV Community by Nizar (@nizarmah).</description>
    <link>https://dev.to/nizarmah</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F5022%2Fbeba2e3e-be24-4d63-afbc-5f053abeebf0.jpeg</url>
      <title>DEV Community: Nizar</title>
      <link>https://dev.to/nizarmah</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nizarmah"/>
    <language>en</language>
    <item>
      <title>Mocktender: simplified testing using entry points</title>
      <dc:creator>Nizar</dc:creator>
      <pubDate>Tue, 25 Mar 2025 13:56:21 +0000</pubDate>
      <link>https://dev.to/nizarmah/mocktender-simplified-testing-using-entry-points-256a</link>
      <guid>https://dev.to/nizarmah/mocktender-simplified-testing-using-entry-points-256a</guid>
      <description>&lt;p&gt;Hey folks. It's been a while since my last post...&lt;/p&gt;

&lt;p&gt;What have I been up to, you may ask?&lt;br&gt;
I have been struggling with testing.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://github.com/nizarmah/mocktender/" rel="noopener noreferrer"&gt;this tool&lt;/a&gt; to simplify testing.&lt;br&gt;
And I'm here to share more about it. &lt;/p&gt;
&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;I've learned to test behavior and to isolate integrations so the tests remain quick.&lt;/p&gt;

&lt;p&gt;But now, to test a resolver that creates a post, for example, I would need roughly 3 tests.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first test would start the server with mock handlers, ensuring the route calls the handler.&lt;/li&gt;
&lt;li&gt;The second test would call the handler directly with a DB data stub, ensuring the handler returns the created post.&lt;/li&gt;
&lt;li&gt;The third test would start the database, ensuring the query with fake data creates the post row.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If we were to add notifying subscribers by email, we'd need another one! So, we need an isolated test for every integration. &lt;/p&gt;

&lt;p&gt;Yet, all these tests require maintenance.&lt;/p&gt;
&lt;h2&gt;
  
  
  Introducing mocktender
&lt;/h2&gt;

&lt;p&gt;To address that, I built a tool that traces the code behavior across your layers and isolates the integrations.&lt;/p&gt;

&lt;p&gt;Instead of writing and maintaining 3+ tests, I only need 1. I just need to test the entry-point, which in this case is my server route. &lt;/p&gt;

&lt;p&gt;Mocktender traces how my server route interacts with the handler, how the handler interacts with the database method, and so on...&lt;/p&gt;

&lt;p&gt;Then, mocktender isolates them so that my single test runs similarly to those 3 traditional tests, with each integration isolated (without sacrificing speed).&lt;/p&gt;
&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The code from this example can be &lt;a href="https://github.com/nizarmah/mocktender/tree/main/example" rel="noopener noreferrer"&gt;found here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To demonstrate the example, we'll test a basic HTTP server with a route handler.&lt;/p&gt;

&lt;p&gt;We're only going to handle the &lt;code&gt;/hello&lt;/code&gt; route; otherwise, we'll return 404 not found.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// server.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;helloHandler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./handlers.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IncomingMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ServerResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;helloHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/plain&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/plain&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Not Found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now that we have the server, we want to implement the &lt;code&gt;helloHandler&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It accepts an optional query parameter &lt;code&gt;name&lt;/code&gt; and returns &lt;code&gt;200&lt;/code&gt; status with body &lt;code&gt;Hello, ${name ?? 'world'}!&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// handlers.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;world&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`Hello, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/** @bridge bridges the server request handler with the greet function */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;helloHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Notice the &lt;code&gt;@bridge&lt;/code&gt; tag we added above &lt;code&gt;helloHandler&lt;/code&gt;?&lt;br&gt;
This helps mocktender identify where it should isolate the tests.&lt;/p&gt;

&lt;p&gt;We still need to test the entry-point's behavior.&lt;/p&gt;

&lt;p&gt;So, we'll start the server when we start testing, and close it when we're done testing.&lt;/p&gt;

&lt;p&gt;During the test, we'll call each server route. The following routes should cover all the behaviors of our codebase:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;/hello&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/hello?name=John&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/not-found&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// server.test.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createServer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./server.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TestCase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;want&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;greeting.default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;want&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, world!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;greeting.withName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/hello?name=John&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;want&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, John!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;greeting.notFound&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/not-found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;want&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not Found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;// This test runs as both: end to end, and isolated integration test.&lt;/span&gt;
&lt;span class="c1"&gt;// Test the behavior, record it, and then replay it.&lt;/span&gt;
&lt;span class="c1"&gt;// Replaying the test is great for CI and isolating fixtures.&lt;/span&gt;
&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="nf"&gt;beforeAll&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="nf"&gt;afterAll&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tt&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$desc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__rid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;desc&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`http://localhost:8080&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gotStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gotStatus&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;want&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gotBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gotBody&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;want&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Next up, I need to record the behavior of my codebase.&lt;br&gt;
After adding mocktender's Jest plugin, I can run the following command.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn &lt;span class="nb"&gt;test&lt;/span&gt;:record
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;As a result, the following behaviors file gets generated.&lt;/p&gt;

&lt;p&gt;This file is tracked by version control, so you can know exactly what changes whenever reviewing a pull request.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/app/example/handlers.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;helloHandler&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;           &lt;span class="c1"&gt;// the `@bridge` tagged function&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;greeting.default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;   &lt;span class="c1"&gt;// the first testcase&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;args&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                    &lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;result&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;status&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, world!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;greeting.withName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;   &lt;span class="c1"&gt;// the second testcase&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;args&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/hello?name=John&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                    &lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;result&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;status&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, John!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Finally, whenever I need to simulate the test run again, I can just run the following command.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn test:replay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;It’s in early proof-of-concept stage, dogfooding, with a working example.&lt;/p&gt;

&lt;p&gt;It has a long way to go, so I'd love feedback/contributions—especially on a subject like testing.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nizarmah" rel="noopener noreferrer"&gt;
        nizarmah
      &lt;/a&gt; / &lt;a href="https://github.com/nizarmah/mocktender" rel="noopener noreferrer"&gt;
        mocktender
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Simplified testing using entry-points.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;mocktender&lt;/h1&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Serves mocks.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Mocktender is a test tracer that automatically records code behavior and replays it later, simplifying tests and mocks.&lt;/p&gt;

&lt;p&gt;For example, testing a create post resolver, traditionally I would:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Test the resolver with a DB stub.&lt;/li&gt;
&lt;li&gt;Test the DB integration with fake input.&lt;/li&gt;
&lt;li&gt;Test server integration with a resolver mock.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using mocktender, I would only need to test the entrypoint (the server route). Then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Mocktender records the behavior across the server, resolver, and DB.&lt;/li&gt;
&lt;li&gt;Mocktender automatically isolates each to match traditional tests.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Check &lt;a href="https://github.com/nizarmah/mocktender./example#mocktenderexample" rel="noopener noreferrer"&gt;&lt;code&gt;example&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Early development&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Only a proof of concept right now, but actively being developed.&lt;/p&gt;

&lt;p&gt;If you need it, let me know — &lt;a href="https://github.com/nizarmah/mocktendermailto:nizar.mah99@gmail.com" rel="noopener noreferrer"&gt;nizar.mah99@gmail.com&lt;/a&gt;.
It can be reproduced in different languages.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Objectives&lt;/h2&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Test a codebase through its entrypoints.&lt;/li&gt;
&lt;li&gt;Eventually, only run codebase through tests.&lt;/li&gt;
&lt;li&gt;One day, simulate e2e tests with unit tests.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Technical guide&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Check &lt;a href="https://github.com/nizarmah/mocktender./src#mocktendersrc" rel="noopener noreferrer"&gt;&lt;code&gt;src&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nizarmah/mocktender" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>testing</category>
      <category>productivity</category>
      <category>typescript</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Building an Open Source Realtime Face Recognition Android App</title>
      <dc:creator>Nizar</dc:creator>
      <pubDate>Thu, 21 May 2020 22:17:12 +0000</pubDate>
      <link>https://dev.to/nizarmah/building-an-open-source-face-recognition-android-app-stage-1-1mk7</link>
      <guid>https://dev.to/nizarmah/building-an-open-source-face-recognition-android-app-stage-1-1mk7</guid>
      <description>&lt;p&gt;We've all seen things in movies we wish were real. The first thing that comes to my mind is &lt;a href="https://www.imdb.com/title/tt0133093/" rel="noopener noreferrer"&gt;The Matrix&lt;/a&gt; and the ability to download any skill onto a person's brain. While this is still far from possible, I've always wanted to create futuristic software I've seen in movies.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Kindly let me know in the comments: What's the first thing that comes to mind when you think of technology you've seen in movies or series? &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sadly, we are still far from creating an artificial intelligence as brilliant as the ones in &lt;a href="https://www.imdb.com/title/tt2209764/" rel="noopener noreferrer"&gt;&lt;em&gt;Transcendence&lt;/em&gt;&lt;/a&gt;, &lt;a href="https://www.imdb.com/title/tt0470752/" rel="noopener noreferrer"&gt;&lt;em&gt;Ex Machina&lt;/em&gt;&lt;/a&gt; or &lt;a href="https://www.imdb.com/title/tt0343818/" rel="noopener noreferrer"&gt;&lt;em&gt;I, Robot&lt;/em&gt;&lt;/a&gt;. Even though I would love to start working on something that huge one day, I've also had this desire to build a live face recognition application for a while now.&lt;/p&gt;

&lt;p&gt;I don't remember exactly when the idea came to mind; however, I know that face recognition is a pretty common thing in movies or series. So, I really wanted to start building one I could keep in my pocket.&lt;/p&gt;

&lt;p&gt;So I decided to blog the process of me building one. There might be multiple stages. Small sneak peeks of possible future stages are collecting data on the go, setting up a smarter model, and updating and loading models online through dependency injection.&lt;/p&gt;

&lt;p&gt;For now, we will be creating the code required for the application to detect the faces and communicate with the face recognition model.&lt;/p&gt;

&lt;h5&gt;
  
  
  Here's a quick demo video
&lt;/h5&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/420028513" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I think I should mention that this works with multiple faces in the field of view of the camera at the same time. &lt;em&gt;Sadly, at the time of recording the demo, I was alone.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Separating the Tasks
&lt;/h3&gt;

&lt;p&gt;Before being able to start with the code, we need to envision how the application will be working.&lt;/p&gt;

&lt;p&gt;This is the list of things we need to do, in the following order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Previewing camera frames&lt;/li&gt;
&lt;li&gt;Capturing camera frames&lt;/li&gt;
&lt;li&gt;Face detection&lt;/li&gt;
&lt;li&gt;Highlighting detected faces&lt;/li&gt;
&lt;li&gt;Face recognition&lt;/li&gt;
&lt;li&gt;Labeling highlighted faces&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By building each part separately, we can, later on, improve certain aspects of the application without having to rewrite a lot of code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Previewing Camera Frames
&lt;/h3&gt;

&lt;p&gt;In order to display the camera frames to the user, I used &lt;a href="https://developer.android.com/reference/kotlin/androidx/camera/view/CameraView" rel="noopener noreferrer"&gt;AndroidX CameraView&lt;/a&gt;. This provided a simple view of what the camera sees. Also, it would be bound to the lifecycle of the activity/fragment. It was a better option than implementing my own preview because it resulted in much better FPS.&lt;/p&gt;

&lt;p&gt;However, the camera view can be given different configurations and settings. A factory helped me specify which configuration I wanted to use, and it would get automatically applied to the camera view.&lt;/p&gt;

&lt;p&gt;So, initializing the camera view looked something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;cameraView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;bindToLifecycle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="nd"&gt;@FaceRecognitionFragment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nc"&gt;CameraViewFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;applyConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cameraView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cameraViewConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;h5&gt;
  
  
  &lt;a href="https://github.com/nizarmah/trinity/tree/master/app/src/main/java/me/nizarmah/trinity/utils/camera/view" rel="noopener noreferrer"&gt;Click here to check the Camera View Factory and Configs code&lt;/a&gt;
&lt;/h5&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Capturing Camera Frames
&lt;/h3&gt;

&lt;p&gt;The view was being shown thanks to the &lt;a href="https://developer.android.com/reference/kotlin/androidx/camera/view/CameraView" rel="noopener noreferrer"&gt;AndroidX CameraView&lt;/a&gt;. Yet, I still didn't have access to the frames, which I need to run the face detection model on.&lt;/p&gt;

&lt;p&gt;Luckily, the &lt;a href="https://developer.android.com/training/camerax" rel="noopener noreferrer"&gt;AndroidX CameraX&lt;/a&gt; can analyze images. Following the &lt;a href="https://developer.android.com/training/camerax/analyze" rel="noopener noreferrer"&gt;CameraX Analyze images&lt;/a&gt; documentation, I created my own &lt;code&gt;CameraAnalysisFactory&lt;/code&gt;, which analyzes images according to certain configurations passed to the factory.&lt;/p&gt;

&lt;p&gt;I had to decrease the resolution of the images because the models and the devices and the models we have currently are far from being able to handle high quality pictures fast.&lt;/p&gt;

&lt;p&gt;Thus, in the camera analysis configuration, I specified a low resolution. &lt;strong&gt;While the model is seeing low resolution frames, the user is still seeing great resolution frames in the camera view.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;LowResFaceDetectionCameraAnalysisConfig&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CameraAnalysisConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;resolution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Size&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;240&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;320&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;readerMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ImageAnalysis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ImageReaderMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ImageAnalysis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ImageReaderMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ACQUIRE_LATEST_IMAGE&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I also created a lambda function that receives the camera's image and rotation degrees from the camera frame analyzer, which later on deals with the frame received by the analyzer. Then, initialized a camera analyzer by giving the factory a camera analysis configuration and said lambda function.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;cameraFameAnalyzer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CameraFrameAnalyzerLambdaType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;imageProxy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;cameraFrameAnalysisConfig&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LowResFaceDetectionCameraAnalysisConfig&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;cameraFrameAnalysis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ImageAnalysis&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CameraAnalysisFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCameraAnalysis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;cameraFrameAnalysisConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;analyzer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cameraFameAnalyzer&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now that I had the camera frame analysis object initialized, I had to bind it to our lifecycle, alongside with the camera view.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;CameraX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bindToLifecycle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cameraFrameAnalysis&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;h5&gt;
  
  
  &lt;a href="https://github.com/nizarmah/trinity/tree/master/app/src/main/java/me/nizarmah/trinity/utils/camera/analysis" rel="noopener noreferrer"&gt;Click here to check the Camera Analysis Factory and Configs code&lt;/a&gt;
&lt;/h5&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Face Detection
&lt;/h3&gt;

&lt;p&gt;Since I just made a method to pass the frames from the camera to anything I wanted, I passed those frames onto the face detection model.&lt;/p&gt;

&lt;p&gt;I chose &lt;a href="https://firebase.google.com/docs/ml-kit" rel="noopener noreferrer"&gt;Firebase MLKit&lt;/a&gt; for face detection since it is able to &lt;em&gt;detect&lt;/em&gt; faces and &lt;em&gt;track&lt;/em&gt; them as they move in the camera's field of view.&lt;/p&gt;

&lt;p&gt;Accordingly, I created an abstract face detector object, with the necessary functionality. Meanwhile, the face detector objects inheriting that abstract class will have their own options for the firebase model.&lt;/p&gt;

&lt;p&gt;Simply, I can, then, just initialize the face detector model I want to use.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;faceDetector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FaceDetector&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FaceDetector&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;All that was left was to pass the frames I was getting from the analyzer onto the face detector. Following the &lt;a href="https://firebase.google.com/docs/ml-kit/detect-faces" rel="noopener noreferrer"&gt;Firebase MLKit Face Detection&lt;/a&gt; documentation, I specified the image's rotation and let the model process it.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;cameraFameAnalyzer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CameraFrameAnalyzerLambdaType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;imageProxy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;mediaImage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;imageProxy&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;

    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;imageRotation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;FirebaseVisionImageMetadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ROTATION_0&lt;/span&gt;
        &lt;span class="mi"&gt;90&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;FirebaseVisionImageMetadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ROTATION_90&lt;/span&gt;
        &lt;span class="mi"&gt;180&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;FirebaseVisionImageMetadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ROTATION_180&lt;/span&gt;
        &lt;span class="mi"&gt;270&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;FirebaseVisionImageMetadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ROTATION_270&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Rotation must be 0, 90, 180, or 270."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;mediaImage&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;faceDetector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;processImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mediaImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imageRotation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;faces&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;  &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;h5&gt;
  
  
  &lt;a href="https://github.com/nizarmah/trinity/tree/master/app/src/main/java/me/nizarmah/trinity/utils/face/detector" rel="noopener noreferrer"&gt;Click here to check the Face Detector code&lt;/a&gt;
&lt;/h5&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Highlighting Detected Faces
&lt;/h3&gt;

&lt;p&gt;Since the face detector model returns the faces and the frame read by the images, I sent those faces and their coordinates in the frame to a face highlighter object. The face highlighter object would be responsible for drawing the highlights around the faces.&lt;/p&gt;

&lt;p&gt;Therefore, I created a lambda function, similar to the one passed to the &lt;code&gt;faceDetector.processImage&lt;/code&gt;, where face highlight objects would be assigned to every detected face.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;highlightedFacesLiveData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MutableLiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FaceHighlight&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;()&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;highlightDetectedFaces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FirebaseVisionFace&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;faces&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;highlightedFacesList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FaceHighlight&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;

    &lt;span class="n"&gt;faces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;highlightedFacesList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RectangularFaceHighlight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;highlightedFacesLiveData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;highlightedFacesList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then, I would specify that lambda function as the callback for the &lt;code&gt;faceDetector.processImage&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;faceDetector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;processImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mediaImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imageRotation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;highlightDetectedFaces&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But I wasn't done yet. Before I drew those highlights on top of the camera view, I remembered that the camera view and the frames passed to the face detector don't have the same resolution. Therefore, I had to create a transforming object to transform the coordinates of the face detected and their sizes to match the resolution of the camera view.&lt;/p&gt;

&lt;p&gt;So, it was important to attach the face highlighter to both the camera view and the camera analyzer. The face highlighter would read the size of the camera view and the resolution of the camera analyzer and transform the highlights accordingly.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;highlighterFaces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FaceHighlighter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;findViewById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;highlighter_faces&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;highlighterFaces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attachCameraView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cameraView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cameraViewConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;highlighterFaces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attachCameraAnalysisConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cameraFrameAnalysisConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Following that, I took the face highlights posted through &lt;code&gt;LiveData&lt;/code&gt; and drew them on the canvas.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;highlightedFacesLiveData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Observer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;highlightedFaces&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;highlighterFaces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;highlightedFaces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;highlighterFaces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;highlighterFaces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postInvalidate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;h5&gt;
  
  
  &lt;a href="https://github.com/nizarmah/trinity/tree/master/app/src/main/java/me/nizarmah/trinity/utils/face/highlighter" rel="noopener noreferrer"&gt;Click here to check the Face Highlighter and the Face Highlight Objects&lt;/a&gt;
&lt;/h5&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Face Recognition
&lt;/h3&gt;

&lt;p&gt;The face recognition model was already done previously as a university course project using the &lt;a href="https://scikit-learn.org/stable/modules/generated/sklearn.datasets.fetch_lfw_people.html" rel="noopener noreferrer"&gt;&lt;em&gt;sklearn.fetch_lfw_dataset&lt;/em&gt; dataset&lt;/a&gt;, you can check it on github, &lt;a href="https://github.com/nizarmah/oracle" rel="noopener noreferrer"&gt;Oracle&lt;/a&gt;. &lt;strong&gt;This model will be later on rebuilt with VGGFace2 and improved even further.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Following the &lt;a href="https://firebase.google.com/docs/ml-kit/use-custom-models" rel="noopener noreferrer"&gt;Firebase MLKit Custom Models&lt;/a&gt; documentation, I converted the model I had to a Tensorflow Lite model and created a face classifier object which can initialize that model and communicate with it.&lt;/p&gt;

&lt;p&gt;I needed to give myself the option to switch the model easily later on. So, I created the models as a configuration class so the face classifier object can know the input shape, output shape, labels, and model path (whether local or remote). &lt;strong&gt;For now, the face classifier only supports local models.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Initializing the face classifier was simple, I just get its instance based on the configuration I want to use.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;faceClassifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FaceClassifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FaceClassifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;OracleFaceClassifierConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After the face classifier was initialized, I tried passing every frame's detected faces onto the face classifier, on a separate thread. &lt;strong&gt;This resulted in a lot of lag, which made the face classifier not usable.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In order to solve that issue, I decided to approach this differently. &lt;strong&gt;I ended up running the face classifier only when a new face enters the camera's field of view.&lt;/strong&gt; The highlight would be drawn as soon as the face is detected. However, the classification would run on a separate thread as soon as the face is detected.&lt;/p&gt;

&lt;p&gt;Accordingly, I had to update the &lt;code&gt;highlightDetectedFaces&lt;/code&gt; lambda function by keeping track of the &lt;code&gt;trackingId&lt;/code&gt; given from the firebase face detection model and running the face classification only on newly detected faces or &lt;code&gt;trackingId&lt;/code&gt;s.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;highlightedFacesHashMap&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Face&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;highlightDetectedFaces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;onDetectLambdaType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;faces&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;faces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;highlightedFacesHashMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;containsKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trackingId&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;highlightedFacesHashMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trackingId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;updateFace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;face&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Face&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;highlightedFacesHashMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trackingId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;face&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;viewModelScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;highlightedFacesHashMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trackingId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;face&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;classifyFace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;faceClassifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;highlightedFacesList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FaceHighlight&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
    &lt;span class="n"&gt;highlightedFacesHashMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;highlightedFacesList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LabeledRectangularFaceHighlight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;highlightedFacesLiveData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;highlightedFacesList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;h5&gt;
  
  
  &lt;a href="https://github.com/nizarmah/trinity/tree/master/app/src/main/java/me/nizarmah/trinity/utils/face/classifier" rel="noopener noreferrer"&gt;Click here to check the Face Classifier code&lt;/a&gt;
&lt;/h5&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Labeling Highlighted Faces
&lt;/h3&gt;

&lt;p&gt;I had just ran the face classification the way I wished. The result was coming up slightly delayed at first, but then was smooth while the user continued to move inside the camera's field of view. I just had to draw the label onto the screen for the user to see.&lt;/p&gt;

&lt;p&gt;I already had a highlighter set, which can transform the highlights from small resolution frames to the resolution the view was using. I already had a rectangular highlight drawing around the person's face. And I was already getting the response from the model!&lt;/p&gt;

&lt;p&gt;So I just created a highlight that inherits from my rectangular face highlight object. However, this new highlight checks if the face received by the model has a label or not. &lt;strong&gt;If the face does have a label, the label is drawn, and the highlights were being drawn every frame.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So, I created a new face object, instead of using the one provided by firebase. Simply, that face has a coroutine which is responsible for classifying the face. Once the result of that classification is out for that face, it is stored in that object. &lt;strong&gt;If the face is already in the camera's field of view, the face object doesn't change.&lt;/strong&gt; So, I just wait for the classification to be done, and when it is, the face highlights drawn every frame would recognize that the face object being used has a label. Thus, it would draw the label under the face.&lt;/p&gt;

&lt;p&gt;The face object's classification was shown in the previous code segment. But here it is again...&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;highlightedFacesHashMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trackingId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;face&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;classifyFace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;faceClassifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;h5&gt;
  
  
  &lt;a href="https://github.com/nizarmah/trinity/blob/master/app/src/main/java/me/nizarmah/trinity/utils/face/face/Face.kt" rel="noopener noreferrer"&gt;Click here to check the Face object&lt;/a&gt;
&lt;/h5&gt;
&lt;/blockquote&gt;



&lt;blockquote&gt;
&lt;h5&gt;
  
  
  It is important to note that the code shown in this post is segmented from a &lt;a href="https://github.com/nizarmah/trinity/blob/master/app/src/main/java/me/nizarmah/trinity/app/facerecognition/FaceRecognitionFragment.kt" rel="noopener noreferrer"&gt;fragment, or view&lt;/a&gt;, and a &lt;a href="https://github.com/nizarmah/trinity/blob/master/app/src/main/java/me/nizarmah/trinity/app/facerecognition/FaceRecognitionViewModel.kt" rel="noopener noreferrer"&gt;viewmodel&lt;/a&gt;.
&lt;/h5&gt;
&lt;/blockquote&gt;



&lt;p&gt;If you would like to fork or contribute, feel free to check out the repository.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nizarmah" rel="noopener noreferrer"&gt;
        nizarmah
      &lt;/a&gt; / &lt;a href="https://github.com/nizarmah/trinity" rel="noopener noreferrer"&gt;
        trinity
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Real-Time Face Recognition Android App
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>android</category>
      <category>octograd2020</category>
      <category>devgrad2020</category>
      <category>opensource</category>
    </item>
    <item>
      <title>"Hacking" My Way to Automatic File Injection in Chrome Extensions</title>
      <dc:creator>Nizar</dc:creator>
      <pubDate>Mon, 13 Apr 2020 02:41:39 +0000</pubDate>
      <link>https://dev.to/nizarmah/hacking-my-way-to-automatic-file-injection-in-chrome-extensions-5big</link>
      <guid>https://dev.to/nizarmah/hacking-my-way-to-automatic-file-injection-in-chrome-extensions-5big</guid>
      <description>&lt;p&gt;A couple of days ago, it got to my attention that most websites where I read my articles have bad printable pages. So, I decided to make a chrome extension that "prettifies" the print preview for some popular websites that I print.&lt;/p&gt;

&lt;p&gt;The idea was to write a certain set of rules and/or conditions, which once satisfied tell the extension which CSS file improves the &lt;em&gt;print media&lt;/em&gt; for that page.&lt;/p&gt;

&lt;p&gt;Among those websites were multiple Medium based websites such as TowardsDataScience, Medium, etc.. I had to find a solution that wasn't only &lt;em&gt;url&lt;/em&gt; or &lt;em&gt;host&lt;/em&gt; specific; otherwise, I would end up having to enter &lt;em&gt;every&lt;/em&gt; Medium based website's &lt;em&gt;url&lt;/em&gt; or &lt;em&gt;host&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Thus, the solution was to check if a certain element existed in the page using a CSS &lt;em&gt;selector&lt;/em&gt;, which meant that I had to be able to get the page's HTML source first... Moreover, the CSS &lt;em&gt;print media&lt;/em&gt; file needed to be later on &lt;em&gt;injected&lt;/em&gt; to the page automatically.&lt;/p&gt;

&lt;p&gt;However, &lt;em&gt;injecting&lt;/em&gt; the CSS file &lt;em&gt;programmatically&lt;/em&gt; is done through &lt;a href="https://developer.chrome.com/extensions/tabs#method-insertCSS" rel="noopener noreferrer"&gt;&lt;code&gt;chrome.tabs.insertCSS&lt;/code&gt;&lt;/a&gt;. The function requires the &lt;a href="https://developer.chrome.com/extensions/activeTab" rel="noopener noreferrer"&gt;&lt;code&gt;activeTab&lt;/code&gt; permission&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;According to the &lt;a href="https://developer.chrome.com/extensions/activeTab#invoking-activeTab" rel="noopener noreferrer"&gt;chrome developer api&lt;/a&gt;, user gestures (through clicking a certain action or item, or using a keyboard shortcut command) are necessary to enable &lt;code&gt;activeTab&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Yet again, the file needs to be &lt;em&gt;injected&lt;/em&gt; automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This post will be explaining how I managed to inject CSS files automatically without using &lt;code&gt;activeTab&lt;/code&gt; permission or &lt;code&gt;chrome.tabs.insertCSS&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here are the  approaches I took, in order:&lt;/p&gt;

&lt;h3&gt;
  
  
  The Basic
&lt;/h3&gt;

&lt;p&gt;The basic approach is the &lt;a href="https://developer.chrome.com/extensions/activeTab" rel="noopener noreferrer"&gt;&lt;code&gt;activeTab&lt;/code&gt; permission&lt;/a&gt; approach. Unfortunately, there is another problem to it, other than &lt;em&gt;injecting&lt;/em&gt; the CSS file.&lt;/p&gt;

&lt;p&gt;Getting the page's HTML source is not possible because the chrome developer api does not have any method to get a certain tab's HTML document. Consequently, I had to &lt;em&gt;inject&lt;/em&gt; JS to the tab to &lt;em&gt;query&lt;/em&gt; the &lt;em&gt;selector&lt;/em&gt; and check if the element exists.&lt;/p&gt;

&lt;p&gt;This prevented me from being able to check if a CSS &lt;em&gt;selector&lt;/em&gt; matches an element in the page, or even &lt;em&gt;inject&lt;/em&gt; the CSS &lt;em&gt;print media&lt;/em&gt; file, &lt;strong&gt;unless I interact with the &lt;em&gt;action&lt;/em&gt;&lt;/strong&gt; to enable &lt;code&gt;activeTab&lt;/code&gt; permission on that tab.&lt;/p&gt;

&lt;p&gt;So clearly, I needed a different solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Fantasy
&lt;/h3&gt;

&lt;p&gt;Luckily, the &lt;strong&gt;fantasy&lt;/strong&gt; unveiled itself to me while reading their &lt;a href="https://developer.chrome.com/extensions/devguide" rel="noopener noreferrer"&gt;developer guide&lt;/a&gt;. The thing that caught my eye was  &lt;a href="https://developer.chrome.com/extensions/declarativeContent" rel="noopener noreferrer"&gt;&lt;code&gt;chrome.declarativeContent&lt;/code&gt; api&lt;/a&gt;. It had everything I could ever dream of...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.chrome.com/extensions/declarativeContent#type-PageStateMatcher" rel="noopener noreferrer"&gt;&lt;code&gt;PageStateMatcher&lt;/code&gt;&lt;/a&gt; that supports CSS &lt;em&gt;matching&lt;/em&gt; and &lt;em&gt;pageUrl matching&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.chrome.com/extensions/declarativeContent#type-RequestContentScript" rel="noopener noreferrer"&gt;&lt;code&gt;RequestContentScript&lt;/code&gt;&lt;/a&gt; that supports &lt;em&gt;injecting&lt;/em&gt; CSS and JS files &lt;strong&gt;after the rules and/or conditions were satisfied&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Please note that this api requires the use of the &lt;code&gt;declarativeContent&lt;/code&gt; permission.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So this approach would work in the following way&lt;/p&gt;

&lt;h5&gt;
  
  
  How It Works
&lt;/h5&gt;

&lt;ol&gt;
&lt;li&gt;Chrome checks for the rules defined in the extension&lt;/li&gt;
&lt;li&gt;For every rule, if one of the conditions or &lt;code&gt;PageStateMatcher&lt;/code&gt; is satisfied, then Chrome executes the actions specified in the &lt;em&gt;rule&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, here's the rule I &lt;strong&gt;&lt;em&gt;would&lt;/em&gt;&lt;/strong&gt; be using for Medium based websites...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;conditions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;declarativeContent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PageStateMatcher&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;css&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;meta[property='og:site_name'][content='Medium']&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;declarativeContent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RequestContentScript&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;css&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;css/medium.com.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;h5&gt;
  
  
  &lt;a href="https://github.com/nizarmah/fineprint/blob/declarativeContent.RequestContentScript/background.js" rel="noopener noreferrer"&gt;Check the whole code on GitHub&lt;/a&gt;
&lt;/h5&gt;
&lt;/blockquote&gt;

&lt;p&gt;Oh, yes &lt;strong&gt;&lt;em&gt;would&lt;/em&gt;&lt;/strong&gt; be, because according to the api that action is &lt;strong&gt;not supported on stable builds of Chrome&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Since Chrome 38.&lt;/p&gt;

&lt;p&gt;Declarative event action that injects a content script.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WARNING:&lt;/strong&gt;  This action is still experimental and is not supported on stable builds of Chrome.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;I tried so hard and got so far, but in the end it didn't even matter&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The "Hack" Fantasy
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;fantasy&lt;/strong&gt; approach was just too good to go unnoticed and ignored.  It was the solution I needed, an automatic CSS file injection. Hence, I needed to implement it myself in a &lt;em&gt;hacky&lt;/em&gt; way. To implement that &lt;em&gt;hacky&lt;/em&gt; approach, I used two different apis.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/extensions/messaging#simple" rel="noopener noreferrer"&gt;Simple One-Time Messaging Requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/extensions/content_scripts#declaratively" rel="noopener noreferrer"&gt;Declaratively Injected Content Scripts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Although we are using those apis, it is important to note that no permissions are needed in &lt;code&gt;manifest.json&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Additionally, the rules and/or conditions are defined in a similar way to &lt;code&gt;chrome.declarativeContent&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Rule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;conditions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Condition&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;css&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;meta[property='og:site_name'][content='Medium']&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;cssFiles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;medium.com.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;h5&gt;
  
  
  &lt;a href="https://github.com/nizarmah/fineprint/blob/master/page_rules.js" rel="noopener noreferrer"&gt;Check the whole code on GitHub&lt;/a&gt;
&lt;/h5&gt;
&lt;/blockquote&gt;

&lt;p&gt;So here's how the hacky implementation worked.&lt;/p&gt;

&lt;h5&gt;
  
  
  Thought Process
&lt;/h5&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;&lt;code&gt;injector.js&lt;/code&gt;&lt;/em&gt; that is loaded to all pages (&lt;code&gt;&amp;lt;all_urls&amp;gt;&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;&lt;code&gt;injector.js&lt;/code&gt;&lt;/em&gt; sends to the extension

&lt;ul&gt;
&lt;li&gt;page &lt;code&gt;window.location&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;page &lt;code&gt;document&lt;/code&gt; object&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Extension's &lt;em&gt;&lt;code&gt;background.js&lt;/code&gt;&lt;/em&gt; receives the message from the page&lt;/li&gt;
&lt;li&gt;Extension's &lt;em&gt;&lt;code&gt;validator.js&lt;/code&gt;&lt;/em&gt; checks if any rules and/or conditions satisfies the page depending on:

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;pageUrl&lt;/em&gt; &lt;em&gt;matching&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;CSS &lt;em&gt;matching&lt;/em&gt; by &lt;em&gt;selector&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If a rule satisfies a page, the extension's &lt;em&gt;&lt;code&gt;background.js&lt;/code&gt;&lt;/em&gt; sends back the &lt;em&gt;path&lt;/em&gt; of all the &lt;code&gt;cssFiles&lt;/code&gt; associated with that &lt;code&gt;Rule&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;&lt;code&gt;injector.js&lt;/code&gt;&lt;/em&gt; receives the response from the extension's &lt;em&gt;&lt;code&gt;background.js&lt;/code&gt;&lt;/em&gt; and adds the CSS file paths to the page.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;h5&gt;
  
  
  Please note that there are multiple &lt;code&gt;manifest.json&lt;/code&gt; attributes that need to be added in order to make all that possible. However, for the sake of keeping this short, &lt;strong&gt;the code is commented in detail on GitHub&lt;/strong&gt;.
&lt;/h5&gt;
&lt;h5&gt;
  
  
  &lt;a href="https://github.com/nizarmah/fineprint" rel="noopener noreferrer"&gt;Check the whole implementation on GitHub&lt;/a&gt;
&lt;/h5&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Special thanks to &lt;a href="https://slice.zone/" rel="noopener noreferrer"&gt;slice&lt;/a&gt; for his review and constructive comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>javascript</category>
      <category>chromeextension</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Auto Pi Finder or Any Device Really</title>
      <dc:creator>Nizar</dc:creator>
      <pubDate>Sun, 07 May 2017 13:31:01 +0000</pubDate>
      <link>https://dev.to/nizarmah/auto-pi-finder-or-any-device-really</link>
      <guid>https://dev.to/nizarmah/auto-pi-finder-or-any-device-really</guid>
      <description>&lt;p&gt;The aim of this is to demonstrate how to automatically find a Pi on a network using an Android application.&lt;/p&gt;

&lt;p&gt;To understand what is needed, we should discuss ARP tables and a fast segment of ip addresses, because why not.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's an ARP Table ?
&lt;/h3&gt;

&lt;p&gt;Well, ARP stands for Address Resolution Protocol. It links network addresses to physical addresses, in other words, links every ip Address to a mac Address.&lt;/p&gt;

&lt;p&gt;That happens when two devices interact on a network, during that, the mac address of each device is shared with the other under a specific ip address and linking it accordingly.&lt;/p&gt;

&lt;p&gt;But of course, storing all those interactions can clog up a device's memory; therefore, the ARP table is cleared from time to time.&lt;br&gt;
But I still didn't explain what an ARP table; it is just a file containing each ip address and the mac address accompanying it.&lt;/p&gt;

&lt;p&gt;ARP table get cleared as we said, but this differs between devices and how much they can handle. Android phones being, well, android phones, the table is cleared really frequently ( gonna approximate 5 mins ). And not having &lt;code&gt;nmap&lt;/code&gt; doesn't help in listing the devices on the same network.&lt;/p&gt;

&lt;p&gt;Moreover, who wouldn't like to check what devices are connected onto one's internet on one's phone.&lt;br&gt;
Well, I don't know about you, but it was crucial to start the project I'm working on.&lt;/p&gt;
&lt;h3&gt;
  
  
  Fast Introduction to IP Addresses
&lt;/h3&gt;

&lt;p&gt;Well, there are multiple classes of ip addresses that have multiple numbers of hosts. Let's say ip addresses are of the format &lt;code&gt;a.b.c.d&lt;/code&gt;. Well, &lt;code&gt;a&lt;/code&gt; specifies the class.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;a&lt;/code&gt; ranging between [1, 126], the hosts are about 6 million. (class a)&lt;br&gt;
Ignore for when &lt;code&gt;a&lt;/code&gt; = 127, it is the local network address.&lt;br&gt;
For &lt;code&gt;a&lt;/code&gt; ranging between [128, 191], the hosts are about 300 thousand. (class b)&lt;br&gt;
For &lt;code&gt;a&lt;/code&gt; ranging between [192, 223], the hosts are actually 253. (class c)&lt;/p&gt;

&lt;p&gt;Now the latter is called class c. There are 2 others, but they aren't used for private ip addresses.&lt;/p&gt;

&lt;p&gt;Now, why are the hosts like that ? Well, &lt;code&gt;b&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;, and &lt;code&gt;d&lt;/code&gt; vary between being constant and alternating for each.&lt;/p&gt;

&lt;p&gt;For class a, &lt;code&gt;b&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;, and &lt;code&gt;d&lt;/code&gt; are varying. They vary between 0 and 255; however, there are some exceptions for &lt;code&gt;d&lt;/code&gt;.&lt;br&gt;
For class b, &lt;code&gt;c&lt;/code&gt; and &lt;code&gt;d&lt;/code&gt; are varying.&lt;br&gt;
For class c, &lt;code&gt;d&lt;/code&gt; is only varying.&lt;/p&gt;
&lt;h3&gt;
  
  
  So let's start!
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that this only works for private ips networks of class c ( 192 - 223 : first part of the ip address )&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But what's the fastest form of interaction between two devices and the easiest, well, pinging is!&lt;br&gt;
Setting out the process, it would go from checking online hosts, to pinging them, then collecting the ARP table.&lt;/p&gt;
&lt;h4&gt;
  
  
  Checking online hosts
&lt;/h4&gt;

&lt;p&gt;To check for online hosts, I worked on pinging all the hosts available on a network.&lt;br&gt;
This is rather time consuming, but I couldn't find any alternative to this. Pinging the broadcasting ip of a network isn't faster too. Therefore, I had to limit it to a class C private ip address network.&lt;/p&gt;

&lt;p&gt;You can do that using Java, ping all the ip addresses from 1 to 254.&lt;br&gt;
I instead chose to do all the stuff using Android Shell.&lt;/p&gt;

&lt;p&gt;We need to check the available hosts and then reping them, the reason is explain in the next step. To do that, we need to save which ones gave us a response.&lt;br&gt;
That was done using the following terminal command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;((ping -c 1 192.168.1.etc) &amp;gt; /dev/null) &amp;amp;&amp;amp; (echo "up") || (echo "down")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But wait on me, Android Shell has no bash automatically, so this command won't work. Thus, you have to include the sh tag with it.&lt;br&gt;
Now to make it more efficient, I went ahead and made it almost Async. That way, all the devices that will give me a response give it at the same time.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Due to async, my counter bugged when two responses returned at the exact exact same time. To avoid that, I made a counter that deals with even and odd numbers just so that consecutive responses are never likely to reduce the counter at the same exact time and thus reducing it only once. ( By calling the counter at the same exact time I'm accessing the same value the variable had twice, and thus not reducing it twice, but only once ).&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/*
 Setting a Counter to keep track
 Of the stuff that have finished
 In order to prevent Async Calling for
 Counter, had to delay it without actually
 Delaying it, so divided the Counting
*/
class Counter {
    int i = 0, j = 0;
    public Counter(int m) {
        if (m % 2 &amp;gt; 0) {
            this.i = (int) Math.floor((double) m / 2) + 1;
            this.j = (int) Math.floor((double) m / 2);
        } else {
            this.i = (int) Math.floor((double) m / 2) + 1;
            this.j = (int) Math.floor((double) m / 2);
        }
    }
    public void resize(int i) {
        this.i = i;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;I kept having a bug with one host not returning at all, knowing that 255 would not return in time, I looped from 1 to 255 and proceeded to the next function at 254 responses.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// This is a counter to keep track of what is done pinging
final Counter pingerCounter;
/*
 Asyncing ( the easy way ) Pinging each IP Address in order to
 Collect active ones with their Mac Address in ARP Cache Tables
 When done pinging, ARP runs to get the IP Address
 */
final Thread pinger;
pingerCounter = new Counter(254);
class Pinger implements Runnable {
    int y = 0, tempY = 0;

    Pinger (int y) {
        this.y = y;
    }

    public void run() {
        StringBuffer output = new StringBuffer();
        Process ping;
        try {
            /*
             Commands there cause ADB Shell on Android
             Doesn't support god damn inline operands
             So had to do it with Bash
             */
            String[] command = { "sh", "-c", "((ping -c 1 " + ipString + this.y + ") &amp;gt; /dev/null) &amp;amp;&amp;amp; (echo 'up') || (echo 'down')" };
            ping = Runtime.getRuntime().exec(command);

            /*
             Setting TempY to store the valid Y
             Instead of storing the one after it
             */
            this.tempY = this.y;

            /*
             Here we're making sure that we end
             Up running all pings almost async
             */
            this.y -= 1;
            if (this.y &amp;gt; 0) new Thread(new Pinger(this.y)).start();

            ping.waitFor();

            // Log.i("PiFinder", "Checked host on " + ipString + this.tempY);
            // Log.i("PiFinder", (pingerCounter.i - 1) + " hosts to be check");

            // Grabbing output to know whether the address is up
            // So that we can easily read it into ARP Tables
            InputStream inStream = ping.getInputStream();
            // Needed to observe errors, thus this is here
            // InputStream errorStream = ping.getErrorStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inStream));
            String line = "";
            StringBuilder response = new StringBuilder();

            while ((line = bufferedReader.readLine()) != null) {
                response.append(line);

                if (line.equals("up")) {
                    Log.i("PiFinder", "Available host on " + ipString + this.tempY);
                    pingables.add(ipString + this.tempY);
                }
            }

            /*
             Here we're checking for how many pings
             Were completed, so that we proceed
             In order to prevent Async Calling for
             Counter, had to delay it without actually
             Delaying it, so divided the Counting
             */
            if ((this.tempY % 2) == 1)
                pingerCounter.i--;
            else pingerCounter.j--;
            if ((pingerCounter.i + pingerCounter.j) == 0)
                new Thread(new Pingable(pingables.size())).start();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
pinger = new Thread(new Pinger(255));
pinger.start();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Pinging Online Hosts
&lt;/h4&gt;

&lt;p&gt;When I said I was gonna talk about ARP tables, I didn't mention everything.&lt;br&gt;
There's a surprise I had to mention here, which is, that ARP tables have a specific number of lines sadly.&lt;br&gt;
So pinging all the hosts would get some forgotten and buried under their brothers. We don't want that! So, we have to reping them.&lt;/p&gt;

&lt;p&gt;Now note that, I assumed that there won't be more than 90 online hosts on a network of a person using my application, so I didn't go for measures to deal with more than 93 hosts.&lt;br&gt;
Why 93 ? Because, after collecting the length of ARP tables of the android devices in my vicinity, I ended up with 93 on all of them. So, I assumed that ARP tables are gonna have a maximum of 93 devices.&lt;/p&gt;

&lt;p&gt;So repinging them is similar to the process before using the &lt;code&gt;-c1&lt;/code&gt;. But no need for the &lt;code&gt;sh&lt;/code&gt;, even though I included it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// List of Pingable Addresses or Online Hosts
final ArrayList&amp;lt;String&amp;gt; pingables = new ArrayList&amp;lt;String&amp;gt;();

// This is a counter to keep track of what is done pinging
final Counter pingableCounter = new Counter(0);
/*
 Repinging the Available Hosts to refresh
 the ARP Table Cache to make sure it's a Pi
 */
class Pingable implements Runnable {
    int i = 0, tempI = 0;

    Pingable(int m) {
        if (m == pingables.size()) {
            this.i = m - 1;
            pingableCounter.resize(m - 1);
        } else this.i = m;
    }

    public void run() {
        try {
            if (pingables.size() == 0)
                arp.start();
            else {
                String[] command = { "sh", "-c", "ping -c 1 " + pingables.get(this.i) };
                Process ping = Runtime.getRuntime().exec(command);

                // Setting TempY to store the valid I
                // Instead of storing the one after it
                this.tempI = this.i;

                // Here we're making sure that we end
                // Up running all pings almost async
                this.i -= 1;
                if (this.i &amp;gt; -1) new Thread(new Pingable(this.i)).start();

                Log.i("PiFinder", "Pinged host on " + pingables.get(this.tempI));

                ping.waitFor();

                /*
                 Here we're checking for how many pings
                 Were completed, so that we proceed
                 In order to prevent Async Calling for
                 Counter, had to delay it without actually
                 Delaying it, so divided the Counting
                 */
                if ((this.tempI % 2) == 0)
                    pingableCounter.i--;
                else pingableCounter.j--;
                if ((pingableCounter.i + pingableCounter.j) == 0)
                    arp.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Collecting ARP table
&lt;/h4&gt;

&lt;p&gt;There's a specific file in the Android root folders where the table is cached.&lt;br&gt;
The file is in &lt;code&gt;/proc/net/arp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Well, in my case, I wanted to find a specific device in that ARP table. I was searching for a Raspberry Pi. Oh well, damn it, I guess now you know I'm working on something for the Raspberry Pi.&lt;/p&gt;

&lt;p&gt;Anyway, I added some operands to use &lt;code&gt;grep&lt;/code&gt; and search for the specific mac address a raspberry pi starts with, the famous &lt;code&gt;b8:27:eb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Thus what I did was, the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/*
 After getting the online hosts use ARP to get mac addresses
 Knowing that Pis start with B8:27:EB, group them accordingly
 This runs after the bottom thread pinger runs
 */
class ARP implements Runnable {
    public void run() {

        try {
            /*
             Commands there cause ADB Shell on Android
             Doesn't support god damn inline operands
             So had to do it with Bash
             */
            String[] command = { "sh", "-c", "arp -vn | grep -i ' b8:27:eb'" };
            Process arpa = Runtime.getRuntime().exec(command);

            arpa.waitFor();

            Log.i("PiFinder", "Collected ARP Table");

            // Read out available Pi addresses
            InputStream inStream = arpa.getInputStream();
            // Needed to observe errors, thus this is here
            // InputStream errorStream = ping.getErrorStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inStream));
            String line = "";
            StringBuilder response = new StringBuilder();

            ArrayList&amp;lt;ArrayList&amp;lt;String&amp;gt;&amp;gt; pis = new ArrayList&amp;lt;ArrayList&amp;lt;String&amp;gt;&amp;gt;();

            /*
             Since each line is an address, then
             Execute on each line read by buffer
             Then split to get the necessary fields
             */
            while ((line = bufferedReader.readLine()) != null) {
                response.append(line);

                String[] tempLine = line.split("\\s+");

                ArrayList&amp;lt;String&amp;gt; pi = new ArrayList&amp;lt;String&amp;gt;();
                pi.add(tempLine[1].substring(1, tempLine[1].length() - 1));
                pi.add(tempLine[3]);

                pis.add(pi);
            }
                if (pis.size() == 0) {
                    Log.i("PiFinder", "No Pis found");
                    // Use a callback function here (negative)
                } else { // Use a callback function here (positive) }
        } catch (IOException e){
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
final Thread arp = new Thread(new ARP());
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if you don't wish to collect any specific something, you can read the file with Java. You can also go for removing the part after &lt;code&gt;arp -vn&lt;/code&gt; and then change the collection of each line to be specific device with the mac and ip address.&lt;/p&gt;

&lt;h5&gt;
  
  
  But what about the ip field we're missing ?!
&lt;/h5&gt;

&lt;p&gt;I'm sorry about this, I forgot about it...&lt;br&gt;
Here it is.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WifiManager manager = (WifiManager) getApplicationContext().getSystemService(getApplicationContext().WIFI_SERVICE);
WifiInfo info = manager.getConnectionInfo();

long infoIp = info.getIpAddress();

String address = (infoIp &amp;amp; 0xFF) +
        "." + ((infoIp &amp;gt;&amp;gt; 8) &amp;amp; 0xFF) +
        "." + ((infoIp &amp;gt;&amp;gt; 16) &amp;amp; 0xFF) +
        "." + ((infoIp &amp;gt;&amp;gt; 24) &amp;amp; 0xFF);

String[] ip = address.split("\\.");
ipAddress = new String[]{ ip[0], ip[1], ip[2] };

for (int i = 0; i &amp;lt; ipAddress.length; i++)
    ipString = ipString + ipAddress[i] + ".";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And declare those globally...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;String[] ipAddress;
String ipString = "";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well, this was my journey. I hope my tutorial was clear and not abstract.&lt;br&gt;
I've tested the code and pretty sure it works.&lt;br&gt;
For them all in one place, use this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    String[] ipAddress;
    String ipString = "";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_process);

        findMePi();
    }

    private void findMePi() {
        WifiManager manager = (WifiManager) getApplicationContext().getSystemService(getApplicationContext().WIFI_SERVICE);
        WifiInfo info = manager.getConnectionInfo();

        long infoIp = info.getIpAddress();

        String address = (infoIp &amp;amp; 0xFF) +
                "." + ((infoIp &amp;gt;&amp;gt; 8) &amp;amp; 0xFF) +
                "." + ((infoIp &amp;gt;&amp;gt; 16) &amp;amp; 0xFF) +
                "." + ((infoIp &amp;gt;&amp;gt; 24) &amp;amp; 0xFF);

        String[] ip = address.split("\\.");
        ipAddress = new String[]{ ip[0], ip[1], ip[2] };

        for (int i = 0; i &amp;lt; ipAddress.length; i++)
            ipString = ipString + ipAddress[i] + ".";

        class Counter {
            int i = 0, j = 0;
            public Counter(int m) {
                if (m % 2 &amp;gt; 0) {
                    this.i = (int) Math.floor((double) m / 2) + 1;
                    this.j = (int) Math.floor((double) m / 2);
                } else {
                    this.i = (int) Math.floor((double) m / 2) + 1;
                    this.j = (int) Math.floor((double) m / 2);
                }
            }
            public void resize(int i) {
                this.i = i;
            }
        }

        class ARP implements Runnable {
            public void run() {

                try {
                    String[] command = { "sh", "-c", "arp -vn | grep -i ' b8:27:eb'" };
                    Process arpa = Runtime.getRuntime().exec(command);

                    arpa.waitFor();

                    Log.i("PiFinder", "Collected ARP Table");

                    // Read out available Pi addresses
                    InputStream inStream = arpa.getInputStream();
                    // Needed to observe errors, thus this is here
                    // InputStream errorStream = ping.getErrorStream();
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inStream));
                    String line = "";
                    StringBuilder response = new StringBuilder();

                    ArrayList&amp;lt;ArrayList&amp;lt;String&amp;gt;&amp;gt; pis = new ArrayList&amp;lt;ArrayList&amp;lt;String&amp;gt;&amp;gt;();

                    while ((line = bufferedReader.readLine()) != null) {
                        response.append(line);

                        String[] tempLine = line.split("\\s+");

                        ArrayList&amp;lt;String&amp;gt; pi = new ArrayList&amp;lt;String&amp;gt;();
                        pi.add(tempLine[1].substring(1, tempLine[1].length() - 1));
                        pi.add(tempLine[3]);

                        pis.add(pi);
                    }
                    if (pis.size() == 0) {
                        Log.i("PiFinder", "No Pis found");
                        // Use Callback Here ( Negative )
                    } else {
                        // Use Callback Here ( Positive )
                    }
                } catch (IOException e){
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        final Thread arp = new Thread(new ARP());

        final ArrayList&amp;lt;String&amp;gt; pingables = new ArrayList&amp;lt;String&amp;gt;();

        final Counter pingableCounter = new Counter(0);

        class Pingable implements Runnable {
            int i = 0, tempI = 0;

            Pingable(int m) {
                if (m == pingables.size()) {
                    this.i = m - 1;
                    pingableCounter.resize(m - 1);
                } else this.i = m;
            }

            public void run() {
                try {
                    if (pingables.size() == 0)
                        arp.start();
                    else {
                        String[] command = { "sh", "-c", "ping -c 1 " + pingables.get(this.i) };
                        Process ping = Runtime.getRuntime().exec(command);

                        this.tempI = this.i;

                        this.i -= 1;
                        if (this.i &amp;gt; -1) new Thread(new Pingable(this.i)).start();

                        Log.i("PiFinder", "Pinged host on " + pingables.get(this.tempI));

                        ping.waitFor();

                        if ((this.tempI % 2) == 0)
                            pingableCounter.i--;
                        else pingableCounter.j--;
                        if ((pingableCounter.i + pingableCounter.j) == 0)
                            arp.start();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        final Counter pingerCounter;

        final Thread pinger;
        pingerCounter = new Counter(254);
        class Pinger implements Runnable {
            int y = 0, tempY = 0;

            Pinger (int y) {
                this.y = y;
            }

            public void run() {
                StringBuffer output = new StringBuffer();
                Process ping;
                try {
                    String[] command = { "sh", "-c", "((ping -c 1 " + ipString + this.y + ") &amp;gt; /dev/null) &amp;amp;&amp;amp; (echo 'up') || (echo 'down')" };
                    ping = Runtime.getRuntime().exec(command);

                    this.tempY = this.y;

                    this.y -= 1;
                    if (this.y &amp;gt; 0) new Thread(new Pinger(this.y)).start();

                    ping.waitFor();
                    InputStream inStream = ping.getInputStream();
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inStream));
                    String line = "";
                    StringBuilder response = new StringBuilder();

                    while ((line = bufferedReader.readLine()) != null) {
                        response.append(line);

                        if (line.toString().equals("up")) {
                            Log.i("PiFinder", "Available host on " + ipString + this.tempY);
                            pingables.add(ipString + this.tempY);
                        }
                    }

                    if ((this.tempY % 2) == 1)
                        pingerCounter.i--;
                    else pingerCounter.j--;
                    if ((pingerCounter.i + pingerCounter.j) == 0)
                        new Thread(new Pingable(pingables.size())).start();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        pinger = new Thread(new Pinger(255));
        pinger.start();
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope my code isn't that bad.&lt;/p&gt;

</description>
      <category>arp</category>
      <category>ipaddress</category>
      <category>android</category>
      <category>java</category>
    </item>
    <item>
      <title>Hi, I'm Nizar</title>
      <dc:creator>Nizar</dc:creator>
      <pubDate>Sat, 25 Feb 2017 20:34:40 +0000</pubDate>
      <link>https://dev.to/nizarmah/hi-im-nizar</link>
      <guid>https://dev.to/nizarmah/hi-im-nizar</guid>
      <description>&lt;p&gt;I have been coding since I was 12.&lt;/p&gt;

&lt;p&gt;You can find me on Twitter as &lt;a href="https://twitter.com/nizarmah_" rel="noopener noreferrer"&gt;@nizarmah_&lt;/a&gt;&lt;br&gt;
You can also check out my &lt;a href="https://nizarmah.me/" rel="noopener noreferrer"&gt;website&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I eat a lot, I talk a lot, and I work a lot.&lt;/p&gt;

&lt;p&gt;I like to work on my own libraries and apis to use.&lt;/p&gt;

&lt;p&gt;I also build websites and apps for the fun of it including designing them.&lt;/p&gt;

&lt;p&gt;Getting into AI without AI knowledge.&lt;br&gt;
Tough road but slow and steady.&lt;/p&gt;

&lt;p&gt;Have a good day!&lt;/p&gt;

</description>
      <category>introduction</category>
    </item>
  </channel>
</rss>
