<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Posts on GeekyHub</title>
    <link>https://www.geekyhub.in/post/</link>
    <description>Recent content in Posts on GeekyHub</description>
    <generator>Hugo -- 0.148.1</generator>
    <language>en</language>
    <lastBuildDate>Thu, 21 Aug 2025 17:39:22 +0530</lastBuildDate>
    <atom:link href="https://www.geekyhub.in/post/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>How to run any local project on HTTPS without any hassle</title>
      <link>https://www.geekyhub.in/post/how-to-run-any-local-project-on-https-without-any-hassle/</link>
      <pubDate>Thu, 21 Aug 2025 16:56:19 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/how-to-run-any-local-project-on-https-without-any-hassle/</guid>
      <description>A fast, simple way to run any local project on HTTPS with a custom local domain. Works on macOS and Linux.</description>
      <content:encoded><![CDATA[<p>Modern browsers expect HTTPS. Cookies with <code>Secure</code>, OAuth callbacks, Service Workers, HTTP/2, and many APIs either require or work better with HTTPS.</p>
<p>I created <code>local-https</code>, a simple tool to run any local project on HTTPS with a custom local domain.</p>
<ul>
<li>No browsers hacks</li>
<li>No changing your app’s code</li>
<li>Works on macOS and Linux</li>
</ul>
<p>GitHub: <a href="https://github.com/vikas-0/local-https">https://github.com/vikas-0/local-https</a></p>
<hr>
<h2 id="what-is-local-https">What is local-https?</h2>
<p><code>local-https</code> is a small Ruby CLI that:</p>
<ul>
<li>Generates trusted local TLS certificates with <a href="https://github.com/FiloSottile/mkcert">mkcert</a></li>
<li>Maps your domain to 127.0.0.1 in <code>/etc/hosts</code></li>
<li>Runs an HTTPS reverse proxy (WEBrick) that forwards to your local app</li>
<li>Supports multiple domains via SNI</li>
<li>Optionally redirects HTTP (port 80) to HTTPS (port 443)</li>
</ul>
<p>You get a local URL like <code>https://myapp.test</code> that points to your app on <code>localhost:3000</code>.</p>
<hr>
<h2 id="quick-start">Quick start</h2>
<p>Requirements:</p>
<ul>
<li>macOS or Linux</li>
<li>Ruby 3.0+</li>
<li><code>sudo</code> access for binding to ports 443/80 and editing <code>/etc/hosts</code></li>
</ul>
<p>Install:</p>
<p>Homebrew (Tap):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>brew tap vikas-0/tap
</span></span><span style="display:flex;"><span>brew install vikas-0/tap/local-https
</span></span></code></pre></div><p>Manual (from source):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>git clone https://github.com/vikas-0/local-https
</span></span><span style="display:flex;"><span>cd local-https
</span></span><span style="display:flex;"><span>./install.sh
</span></span></code></pre></div><p>Steps:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># 1) Add a mapping (domain -&gt; local port)</span>
</span></span><span style="display:flex;"><span>local-https add myapp.test <span style="color:#ae81ff">3000</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 2) Start the proxy (binds to :443 and :80 for redirect)</span>
</span></span><span style="display:flex;"><span>sudo local-https start
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 3) Open your app</span>
</span></span><span style="display:flex;"><span>open https://myapp.test
</span></span></code></pre></div><p>Tips:</p>
<ul>
<li>Run in foreground for logs: <code>sudo local-https start --no-daemon</code></li>
<li>Disable HTTP→HTTPS redirect: <code>sudo local-https start --no-redirect-http</code></li>
</ul>
<hr>
<h2 id="works-with-any-tech-stack">Works with any tech stack</h2>
<p>As <code>local-https</code> simply terminates TLS and proxies to your local port. It doesn&rsquo;t require any stack specific configuration.</p>
<ul>
<li>Frontend frameworks (Next.js, React, Vue, Vite, Angular)</li>
<li>Backend APIs (Rails, Django, Flask, Express, Spring)</li>
<li>Webhooks and OAuth callback testing (GitHub, Google, etc.)</li>
</ul>
<hr>
<h2 id="how-it-works-under-the-hood">How it works (under the hood)</h2>
<ul>
<li>Certs are created with mkcert and saved in <code>~/.local-https/certs</code></li>
<li><code>/etc/hosts</code> gets <code>127.0.0.1 myapp.test # local-https</code></li>
<li>The proxy presents the correct certificate per domain (SNI) and forwards traffic to <code>http://127.0.0.1:&lt;port&gt;</code></li>
<li>Config is a simple JSON file at <code>~/.local-https/config.json</code></li>
</ul>
<hr>
<h2 id="configure-your-app-to-accept-your-custom-domain">Configure your app to accept your custom domain</h2>
<p>Most frameworks will just work, but some block unknown hosts in development. Make sure your app accepts the domain you chose (like <code>myapp.test</code>).</p>
<p>Example: Rails (<code>config/environments/development.rb</code>)</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># Allow your custom domain in dev (Rails 6+ Host Authorization)</span>
</span></span><span style="display:flex;"><span>config<span style="color:#f92672">.</span>hosts <span style="color:#f92672">&lt;&lt;</span> <span style="color:#e6db74">&#34;myapp.test&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Optional: if you generate URLs in controllers/mailers, set defaults</span>
</span></span><span style="display:flex;"><span>config<span style="color:#f92672">.</span>action_controller<span style="color:#f92672">.</span>default_url_options <span style="color:#f92672">=</span> { <span style="color:#e6db74">host</span>: <span style="color:#e6db74">&#34;myapp.test&#34;</span>, <span style="color:#e6db74">protocol</span>: <span style="color:#e6db74">&#34;https&#34;</span> }
</span></span><span style="display:flex;"><span>config<span style="color:#f92672">.</span>action_mailer<span style="color:#f92672">.</span>default_url_options     <span style="color:#f92672">=</span> { <span style="color:#e6db74">host</span>: <span style="color:#e6db74">&#34;myapp.test&#34;</span>, <span style="color:#e6db74">protocol</span>: <span style="color:#e6db74">&#34;https&#34;</span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># You do NOT need to force SSL in Rails dev. local-https terminates TLS and</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># forwards plain HTTP to your app on localhost:PORT.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># config.force_ssl = false</span>
</span></span></code></pre></div><p>Notes:</p>
<ul>
<li>If you use multiple local domains, add each one with <code>config.hosts &lt;&lt; &quot;api.test&quot;</code>.</li>
<li>For subdomains, you can whitelist a regex: <code>config.hosts &lt;&lt; /.*\.test/</code>.</li>
<li>Keep your app listening on its normal dev port (e.g., 3000); no TLS changes needed in the app.</li>
</ul>
<hr>
<h2 id="why-https-locally">Why HTTPS locally?</h2>
<ul>
<li>Secure cookies, SameSite=None, Service Workers</li>
<li>OAuth callbacks and cross-origin requests</li>
<li>Matching production behavior</li>
<li>Avoid mixed content warnings and browser feature limits</li>
</ul>
<hr>
<h2 id="frequently-asked-questions-faq">Frequently asked questions (FAQ)</h2>
<ul>
<li>
<p>Can I use multiple domains?</p>
<ul>
<li>Yes. Add as many as you want: <code>local-https add api.test 4000</code>, etc.</li>
</ul>
</li>
<li>
<p>Do I need to change my app code?</p>
<ul>
<li>No. Your app still listens on HTTP (localhost). The proxy handles HTTPS.</li>
</ul>
</li>
<li>
<p>Does this work with Docker?</p>
<ul>
<li>Yes. Point the mapping port to the host port where Docker publishes your service.</li>
</ul>
</li>
<li>
<p>Is this safe?</p>
<ul>
<li>Certificates and config live in your user home. The proxy only listens locally (by default bind <code>0.0.0.0</code>, changeable in code). For public exposure you’d use a proper reverse proxy.</li>
</ul>
</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Unlocking Performance with AsyncJob: Specific Use Cases for I/O-Bound Operations</title>
      <link>https://www.geekyhub.in/post/elasticsearch-opensearch-indexing-performance-rails-jobs/</link>
      <pubDate>Sun, 20 Jul 2025 12:26:17 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/elasticsearch-opensearch-indexing-performance-rails-jobs/</guid>
      <description>Discover how I achieved 5x faster Elasticsearch operations in Rails by switching to AsyncJob. The benchmarks show dramatic performance improvements with 30% less memory usage.</description>
      <content:encoded><![CDATA[<h2 id="the-elasticsearch-scaling-nightmare">The Elasticsearch Scaling Nightmare</h2>
<p>Picture this: Your Rails application is humming along nicely until suddenly, user growth explodes. Great news, right? Not for our job queue.</p>
<p>In a previous application I worked on, we faced significant challenges scaling ActiveJobs, primarily due to numerous Elasticsearch indexing and other I/O-bound tasks. As our user base grew, thousands of small jobs overwhelmed our queue, creating a perfect storm of bottlenecks despite our best efforts at dynamic worker scaling.</p>
<p>We tried all the usual solutions:</p>
<ul>
<li>Increased worker counts (which quickly hit diminishing returns)</li>
<li>Added more powerful servers (hello, spiraling AWS bills)</li>
<li>Optimized database connections (still not enough)</li>
<li>Tweaked job priorities and batching strategies (marginal improvements at best)</li>
</ul>
<p>Yet we still hit hard limits with database connections, memory consumption, and infrastructure costs. The fundamental issue wasn&rsquo;t our implementation,it was the thread-based job processing paradigm itself, which simply wasn&rsquo;t optimized for our I/O-heavy workload.</p>
<h2 id="why-asyncjob-for-io-bound-operations">Why AsyncJob for I/O-Bound Operations?</h2>
<p>Enter <a href="https://github.com/socketry/async-job">AsyncJob</a>, a gem that fundamentally reimagines how Ruby handles concurrent operations by leveraging <strong>Ruby fibers</strong> for cooperative multitasking.</p>
<h3 id="the-thread-vs-fiber-difference">The Thread vs. Fiber Difference</h3>
<p>To understand why this matters, let&rsquo;s break down what happens during an Elasticsearch indexing operation:</p>
<p><strong>With traditional thread-based job processors (like SolidQueue):</strong></p>
<ol>
<li>A thread makes an HTTP request to Elasticsearch</li>
<li>The thread blocks while waiting for a response</li>
<li>The OS must context-switch to another thread</li>
<li>Each thread requires its own memory stack (often 1MB+ per thread)</li>
<li>Thread context switching has significant overhead</li>
</ol>
<p><strong>With fiber-based AsyncJob:</strong></p>
<ol>
<li>A fiber makes an HTTP request to Elasticsearch</li>
<li>The fiber voluntarily yields control while waiting</li>
<li>Another fiber can immediately use the same thread</li>
<li>Fibers are lightweight (a few KB each)</li>
<li>Switching between fibers is extremely efficient</li>
</ol>
<p>This approach is exceptionally efficient for operations that spend most of their time waiting for external resources (I/O-bound), because instead of wasting CPU cycles waiting for responses, the system can process other jobs in the meantime.</p>
<h2 id="getting-started-with-asyncjob">Getting Started with AsyncJob</h2>
<p>Integrating AsyncJob into your Rails application is surprisingly straightforward. The gem provides an adapter for ActiveJob, allowing you to selectively apply it to jobs that would benefit most from fiber-based processing.</p>
<h3 id="installation">Installation</h3>
<p>Add these gems to your Gemfile:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span>gem <span style="color:#e6db74">&#39;async-job&#39;</span>
</span></span><span style="display:flex;"><span>gem <span style="color:#e6db74">&#39;async-job-adapter-active_job&#39;</span>
</span></span><span style="display:flex;"><span>gem <span style="color:#e6db74">&#39;async-job-processor-redis&#39;</span>
</span></span></code></pre></div><p>Then run:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>bundle install
</span></span></code></pre></div><h3 id="configuration">Configuration</h3>
<p>For jobs that would benefit from fiber-based processing, simply specify AsyncJob as the queue adapter:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SearchIndexingJob</span> <span style="color:#f92672">&lt;</span> <span style="color:#66d9ef">ApplicationJob</span>
</span></span><span style="display:flex;"><span>  self<span style="color:#f92672">.</span>queue_adapter <span style="color:#f92672">=</span> <span style="color:#e6db74">:async_job</span>  <span style="color:#75715e"># This job uses fibers</span>
</span></span><span style="display:flex;"><span>  queue_as <span style="color:#e6db74">:default</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">perform</span>(document)
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># Your I/O-heavy code here</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span></code></pre></div><p>You can continue using your existing queue adapter for other jobs:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">CPUIntensiveJob</span> <span style="color:#f92672">&lt;</span> <span style="color:#66d9ef">ApplicationJob</span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># This job still uses your default queue adapter</span>
</span></span><span style="display:flex;"><span>  queue_as <span style="color:#e6db74">:default</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">perform</span>(data)
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># CPU-intensive operations</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span></code></pre></div><p>For more detailed setup instructions, check out the <a href="https://socketry.github.io/async-job-adapter-active_job/guides/getting-started/index">AsyncJob Active Job Adapter documentation</a>.</p>
<h2 id="benchmarking-asyncjob-vs-solidqueue-for-opensearch-operations">Benchmarking AsyncJob vs. SolidQueue for OpenSearch Operations</h2>
<p>To validate my hypothesis about AsyncJob&rsquo;s benefits for I/O-bound operations, I created a comprehensive benchmarking project comparing AsyncJob (fiber-based) with SolidQueue (thread-based) for OpenSearch indexing operations.</p>
<h3 id="the-experiment-setup">The Experiment Setup</h3>
<p>I created two nearly identical jobs:</p>
<ul>
<li><code>JobTest1Job</code> - Using SolidQueue with synchronous HTTP calls</li>
<li><code>JobTest2Job</code> - Using AsyncJob with asynchronous HTTP calls</li>
</ul>
<p>Both jobs perform the same task: indexing documents in OpenSearch. To simulate real-world conditions with network latency, I added a 3-second artificial delay to each OpenSearch request, results were drastically different. But the results here are without any simulated delay.</p>
<p>The full code and detailed results are available in my <a href="https://github.com/vikas-0/jobtest">GitHub repository</a>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#f92672">==========</span> BENCHMARK RESULTS <span style="color:#f92672">==========</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>----- Batch Size: <span style="color:#ae81ff">10</span> documents -----
</span></span><span style="display:flex;"><span>SolidQueue <span style="color:#f92672">(</span>JobTest1Job<span style="color:#f92672">)</span>:
</span></span><span style="display:flex;"><span>  Avg Enqueue Time: 0.18s
</span></span><span style="display:flex;"><span>  Avg Total Time: 1.19s
</span></span><span style="display:flex;"><span>  Avg Throughput: 8.45 docs/second
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>AsyncJob <span style="color:#f92672">(</span>JobTest2Job<span style="color:#f92672">)</span>:
</span></span><span style="display:flex;"><span>  Avg Enqueue Time: 0.06s
</span></span><span style="display:flex;"><span>  Avg Total Time: 1.06s
</span></span><span style="display:flex;"><span>  Avg Throughput: 9.39 docs/second
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Result: AsyncJob was 11.6% faster <span style="color:#66d9ef">for</span> <span style="color:#ae81ff">10</span> documents
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>----- Batch Size: <span style="color:#ae81ff">100</span> documents -----
</span></span><span style="display:flex;"><span>SolidQueue <span style="color:#f92672">(</span>JobTest1Job<span style="color:#f92672">)</span>:
</span></span><span style="display:flex;"><span>  Avg Enqueue Time: 0.59s
</span></span><span style="display:flex;"><span>  Avg Total Time: 1.6s
</span></span><span style="display:flex;"><span>  Avg Throughput: 62.96 docs/second
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>AsyncJob <span style="color:#f92672">(</span>JobTest2Job<span style="color:#f92672">)</span>:
</span></span><span style="display:flex;"><span>  Avg Enqueue Time: 0.24s
</span></span><span style="display:flex;"><span>  Avg Total Time: 1.25s
</span></span><span style="display:flex;"><span>  Avg Throughput: 80.12 docs/second
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Result: AsyncJob was 27.4% faster <span style="color:#66d9ef">for</span> <span style="color:#ae81ff">100</span> documents
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>----- Batch Size: <span style="color:#ae81ff">1000</span> documents -----
</span></span><span style="display:flex;"><span>SolidQueue <span style="color:#f92672">(</span>JobTest1Job<span style="color:#f92672">)</span>:
</span></span><span style="display:flex;"><span>  Avg Enqueue Time: 4.8s
</span></span><span style="display:flex;"><span>  Avg Total Time: 19.17s
</span></span><span style="display:flex;"><span>  Avg Throughput: 54.78 docs/second
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>AsyncJob <span style="color:#f92672">(</span>JobTest2Job<span style="color:#f92672">)</span>:
</span></span><span style="display:flex;"><span>  Avg Enqueue Time: 2.25s
</span></span><span style="display:flex;"><span>  Avg Total Time: 3.25s
</span></span><span style="display:flex;"><span>  Avg Throughput: 307.48 docs/second
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Result: AsyncJob was 489.1% faster <span style="color:#66d9ef">for</span> <span style="color:#ae81ff">1000</span> documents
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">========================================</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">==========</span> RESOURCE USAGE METRICS <span style="color:#f92672">==========</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>----- SOLID_QUEUE Resource Usage -----
</span></span><span style="display:flex;"><span>Memory Usage:
</span></span><span style="display:flex;"><span>  Average: 128.69 MB
</span></span><span style="display:flex;"><span>  Maximum: 177.19 MB
</span></span><span style="display:flex;"><span>CPU Usage:
</span></span><span style="display:flex;"><span>  Average per job: 28.4549 seconds
</span></span><span style="display:flex;"><span>  Total CPU time: 74295.6439 seconds
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>----- ASYNC_JOB Resource Usage -----
</span></span><span style="display:flex;"><span>Memory Usage:
</span></span><span style="display:flex;"><span>  Average: 89.42 MB
</span></span><span style="display:flex;"><span>  Maximum: 118.83 MB
</span></span><span style="display:flex;"><span>CPU Usage:
</span></span><span style="display:flex;"><span>  Average per job: 3.128 seconds
</span></span><span style="display:flex;"><span>  Total CPU time: 5864.9192 seconds
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>----- Comparison -----
</span></span><span style="display:flex;"><span>Memory Usage: AsyncJob uses -30.51% less memory than SolidQueue
</span></span><span style="display:flex;"><span>CPU Usage: AsyncJob uses -92.11% less CPU time than SolidQueue
</span></span></code></pre></div><p>Note: For solid queue, I have used 1 worker with 3 threads, which is a default configuration for solid queue.</p>
<h2 id="analyzing-the-results">Analyzing the Results</h2>
<h3 id="performance-scaling-with-batch-size">Performance Scaling with Batch Size</h3>
<p>The most striking finding from the benchmarks is how AsyncJob&rsquo;s advantage scales with batch size:</p>
<table>
  <thead>
      <tr>
          <th>Batch Size</th>
          <th>Performance Advantage</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>10 documents</td>
          <td>AsyncJob was 11.6% faster</td>
      </tr>
      <tr>
          <td>100 documents</td>
          <td>AsyncJob was 27.4% faster</td>
      </tr>
      <tr>
          <td>1000 documents</td>
          <td>AsyncJob was 489.1% faster</td>
      </tr>
  </tbody>
</table>
<p><strong>Key Insight:</strong> AsyncJob&rsquo;s performance advantage dramatically increases with the number of I/O operations. For small workloads, the difference is noticeable but modest. For large workloads, the difference is transformative.</p>
<h3 id="resource-efficiency">Resource Efficiency</h3>
<p>Beyond raw speed, the resource efficiency gains are equally impressive:</p>
<ul>
<li><strong>Memory Usage:</strong> AsyncJob uses 30.5% less memory than SolidQueue (89.42 MB vs 128.69 MB)</li>
<li><strong>CPU Usage:</strong> AsyncJob uses 92.1% less CPU time than SolidQueue (5,865 seconds vs 74,296 seconds)</li>
</ul>
<p>This translates to significant infrastructure cost savings at scale.</p>
<h2 id="the-secret-sauce-async-http-client">The Secret Sauce: Async HTTP Client</h2>
<p>A key part of my implementation was creating a fiber-aware HTTP client for OpenSearch. Here&rsquo;s a simplified version:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AsyncOpenSearchClient</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">index</span>(<span style="color:#e6db74">index</span>:, id: <span style="color:#66d9ef">nil</span>, <span style="color:#e6db74">body</span>:)
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># Return an Async task that performs the request asynchronously</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">Async</span> <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>task<span style="color:#f92672">|</span>  
</span></span><span style="display:flex;"><span>      <span style="color:#75715e"># Make the request asynchronously</span>
</span></span><span style="display:flex;"><span>      response <span style="color:#f92672">=</span> <span style="color:#66d9ef">Async</span><span style="color:#f92672">::</span><span style="color:#66d9ef">HTTP</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Internet</span><span style="color:#f92672">.</span>post(url, headers, json_body)
</span></span><span style="display:flex;"><span>      
</span></span><span style="display:flex;"><span>      <span style="color:#75715e"># Process response...</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span></code></pre></div><p>This client ensures that while waiting for HTTP responses, other fibers can continue processing, maximizing throughput.</p>
<h2 id="when-to-use-asyncjob">When to Use AsyncJob</h2>
<p>Based on my benchmarks and some research (Google and AI), AsyncJob is ideal for:</p>
<h3 id="1-search-engine-indexing">1. Search Engine Indexing</h3>
<p>This was our primary pain point. AsyncJob transforms Elasticsearch/OpenSearch indexing by efficiently switching fibers during network I/O waits, allowing concurrent indexing operations.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SearchIndexingJob</span> <span style="color:#f92672">&lt;</span> <span style="color:#66d9ef">ApplicationJob</span>
</span></span><span style="display:flex;"><span>  self<span style="color:#f92672">.</span>queue_adapter <span style="color:#f92672">=</span> <span style="color:#e6db74">:async_job</span>
</span></span><span style="display:flex;"><span>  queue_as <span style="color:#e6db74">:default</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">perform</span>(document)
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># Each index operation is an I/O operation where AsyncJob can yield</span>
</span></span><span style="display:flex;"><span>    search_client<span style="color:#f92672">.</span>index(
</span></span><span style="display:flex;"><span>      <span style="color:#e6db74">index</span>: <span style="color:#e6db74">&#34;content&#34;</span>,
</span></span><span style="display:flex;"><span>      id: document<span style="color:#f92672">.</span>id,
</span></span><span style="display:flex;"><span>      <span style="color:#e6db74">body</span>: document<span style="color:#f92672">.</span>to_indexed_json
</span></span><span style="display:flex;"><span>    )
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span></code></pre></div><h3 id="2-api-integrations">2. API Integrations</h3>
<p>Jobs that make external API calls are perfect candidates for AsyncJob:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">NotificationJob</span> <span style="color:#f92672">&lt;</span> <span style="color:#66d9ef">ApplicationJob</span>
</span></span><span style="display:flex;"><span>  self<span style="color:#f92672">.</span>queue_adapter <span style="color:#f92672">=</span> <span style="color:#e6db74">:async_job</span>
</span></span><span style="display:flex;"><span>  queue_as <span style="color:#e6db74">:default</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">perform</span>(user_id, message)
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># Multiple API calls can run concurrently</span>
</span></span><span style="display:flex;"><span>    push_notification_service<span style="color:#f92672">.</span>send(user_id, message)
</span></span><span style="display:flex;"><span>    slack_service<span style="color:#f92672">.</span>notify(message)
</span></span><span style="display:flex;"><span>    analytics_service<span style="color:#f92672">.</span>track(<span style="color:#e6db74">&#34;notification_sent&#34;</span>, user_id)
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span></code></pre></div><h3 id="3-llm-operations">3. LLM Operations</h3>
<p>Large Language Model API calls typically have high latency, making them ideal for AsyncJob:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AIProcessingJob</span> <span style="color:#f92672">&lt;</span> <span style="color:#66d9ef">ApplicationJob</span>
</span></span><span style="display:flex;"><span>  self<span style="color:#f92672">.</span>queue_adapter <span style="color:#f92672">=</span> <span style="color:#e6db74">:async_job</span>
</span></span><span style="display:flex;"><span>  queue_as <span style="color:#e6db74">:default</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">perform</span>(documents)
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># Process multiple documents concurrently</span>
</span></span><span style="display:flex;"><span>    documents<span style="color:#f92672">.</span>each <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>doc<span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span>      summary <span style="color:#f92672">=</span> llm_client<span style="color:#f92672">.</span>summarize(doc<span style="color:#f92672">.</span>content)
</span></span><span style="display:flex;"><span>      doc<span style="color:#f92672">.</span>update(<span style="color:#e6db74">ai_summary</span>: summary)
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span></code></pre></div><h2 id="when-not-to-use-asyncjob">When NOT to Use AsyncJob</h2>
<ol>
<li>
<p><strong>CPU-Intensive Operations</strong>: If your job is CPU-bound (complex calculations, image processing), traditional thread-based queues may perform better.</p>
</li>
<li>
<p><strong>Very Short-Running Jobs</strong>: For jobs that complete in milliseconds with minimal I/O, the overhead of fiber management might not be worth it.</p>
</li>
<li>
<p><strong>Jobs with Non-Fiber-Aware Dependencies</strong>: Some gems and libraries aren&rsquo;t fiber-aware and may block fibers, negating AsyncJob&rsquo;s benefits.</p>
</li>
<li>
<p><strong>Jobs Requiring Robust Error Handling</strong>: AsyncJob currently lacks some of the error handling capabilities found in more mature job processors.</p>
</li>
</ol>
<h2 id="important-considerations-error-handling-with-asyncjob">Important Considerations: Error Handling with AsyncJob</h2>
<p>While AsyncJob offers impressive performance benefits, it&rsquo;s important to be aware of its current limitations in error handling:</p>
<ol>
<li>Limited Built-in Error Handling</li>
<li>Manual Error Logging Required</li>
<li>Monitoring Challenges</li>
</ol>
<h2 id="conclusion-a-game-changer-for-io-heavy-workloads">Conclusion: A Game-Changer for I/O-Heavy Workloads</h2>
<p>For applications with significant I/O-bound job processing needs, AsyncJob represents a paradigm shift in performance and efficiency. My benchmarks show that it&rsquo;s not just marginally better—it can be 5x faster while using 30% less memory and 90% less CPU time.</p>
<p>The best part? You can gradually adopt AsyncJob for specific jobs without changing your entire infrastructure. Start by identifying your most I/O-intensive jobs and convert them first to see immediate benefits.</p>
<p>If your Rails application is struggling with I/O-bound job processing, AsyncJob might just be the solution you&rsquo;ve been looking for.</p>
<p>(Note: I have not used it extensively in production yet, but the benchmarks show promising results.)</p>
]]></content:encoded>
    </item>
    <item>
      <title>How to Use Tiptap&#39;s Collaboration Feature with Rails Action Cable</title>
      <link>https://www.geekyhub.in/post/implementing-a-google-doc-notion-like-collborative-editor-in-rails-react-tiptap/</link>
      <pubDate>Tue, 18 Jun 2024 20:55:00 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/implementing-a-google-doc-notion-like-collborative-editor-in-rails-react-tiptap/</guid>
      <description>Create a collaborative text editor like Notion using Tiptap for rich text, ReactJS for frontend, and Rails with Action Cable for real-time updates. Enable simultaneous editing and instant synchronization across users for a seamless collaborative experience.</description>
      <content:encoded><![CDATA[<p>In this post, we&rsquo;ll walk through setting up Tiptap&rsquo;s collaboration feature with Rails Action Cable and ReactJs. Tiptap is a powerful headless editor built on ProseMirror, and when combined with Y.js, it allows for real-time collaborative editing. We&rsquo;ll use Mantine component library, but it&rsquo;s not mandatory for this setup.</p>
<p>If you prefer to dive directly into the code, check out the example on <a href="https://github.com/vikas-0/collab_demo">Github</a></p>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube-nocookie.com/embed/HXpudWU5FxQ?autoplay=0&amp;controls=1&amp;end=0&amp;loop=1&amp;mute=0&amp;playlist=HXpudWU5FxQ&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<h3 id="prerequisites">Prerequisites</h3>
<p>Ensure you have the following installed:</p>
<ul>
<li>Ruby on Rails</li>
<li>Redis</li>
<li>Node.js and Yarn</li>
<li>Your preferred mehtod of React Setup with Rails</li>
</ul>
<h3 id="step-1-setting-up-mantine">Step 1: Setting Up Mantine</h3>
<p>First, we&rsquo;ll set up Mantine for styling. Follow the <a href="https://mantine.dev/guides/vite/">Mantine guide for Vite</a> to install the necessary packages: (Same method worked for me using esbuild in my setup. You can do it you own way or choose not to use Mantine)</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>yarn add @mantine/core @mantine/hooks @mantine/tiptap @tabler/icons-react @tiptap/react @tiptap/extension-link @tiptap/starter-kit @tiptap/extension-placeholder @tiptap/extension-collaboration-cursor @tiptap/extension-collaboration yjs y-prosemirror
</span></span><span style="display:flex;"><span>yarn add --dev postcss postcss-preset-mantine postcss-simple-vars
</span></span></code></pre></div><blockquote>
<p>Note: This setup includes both Mantine and Tiptap. If you do not require Mantine, skip installing Mantine-related dependencies.</p></blockquote>
<h3 id="step-2-install-rails-dependencies">Step 2: Install Rails Dependencies</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>bundle add redis y-rb_actioncable y-rb
</span></span></code></pre></div><p>Here we are installing Y.js adapter for Ruby and Action Cable.</p>
<h3 id="step-3-configure-tiptap-with-collaboration">Step 3: Configure Tiptap with Collaboration</h3>
<p>In the Tiptap setup, configure the StarterKit with history: false as the Collaboration extension comes with its own history management. Additionally, we’ll add a random color generator for collaboration cursors.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">getRandomColor</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">colors</span> <span style="color:#f92672">=</span> [<span style="color:#e6db74">&#34;#ff901f&#34;</span>, <span style="color:#e6db74">&#34;#ff2975&#34;</span>, <span style="color:#e6db74">&#34;#f222ff&#34;</span>, <span style="color:#e6db74">&#34;#8c1eff&#34;</span>];
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">selectedIndex</span> <span style="color:#f92672">=</span> Math.<span style="color:#a6e22e">floor</span>(Math.<span style="color:#a6e22e">random</span>() <span style="color:#f92672">*</span> (<span style="color:#a6e22e">colors</span>.<span style="color:#a6e22e">length</span> <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>));
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">colors</span>[<span style="color:#a6e22e">selectedIndex</span>];
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">editor</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">useEditor</span>({
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">extensions</span><span style="color:#f92672">:</span> [
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">StarterKit</span>.<span style="color:#a6e22e">configure</span>({ <span style="color:#a6e22e">history</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">false</span> }),
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">Underline</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">Link</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">Superscript</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">SubScript</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">Highlight</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">TextAlign</span>.<span style="color:#a6e22e">configure</span>({ <span style="color:#a6e22e">types</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#39;heading&#39;</span>, <span style="color:#e6db74">&#39;paragraph&#39;</span>] }),
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">Placeholder</span>.<span style="color:#a6e22e">configure</span>({ <span style="color:#a6e22e">placeholder</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;This is placeholder&#39;</span> }),
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">Collaboration</span>.<span style="color:#a6e22e">configure</span>({
</span></span><span style="display:flex;"><span>                document<span style="color:#f92672">:</span> <span style="color:#a6e22e">doc</span> <span style="color:#75715e">// Configure Y.Doc for collaboration
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>            }),
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">CollaborationCursor</span>.<span style="color:#a6e22e">configure</span>({
</span></span><span style="display:flex;"><span>                <span style="color:#a6e22e">provider</span>,
</span></span><span style="display:flex;"><span>                <span style="color:#a6e22e">user</span><span style="color:#f92672">:</span> {
</span></span><span style="display:flex;"><span>                    <span style="color:#a6e22e">name</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;Vikas&#34;</span>,
</span></span><span style="display:flex;"><span>                    <span style="color:#a6e22e">color</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">getRandomColor</span>()
</span></span><span style="display:flex;"><span>                }
</span></span><span style="display:flex;"><span>            })
</span></span><span style="display:flex;"><span>        ]
</span></span><span style="display:flex;"><span>    });
</span></span></code></pre></div><p>Code to connect with websocket provided by ActionCable. Don&rsquo;t worry about the channel creation now, we will create it later. Assuming channel name will be <code>SyncChannel</code> we will add following code. (Here id is hardcoded, as this is just a demo. we won&rsquo;t be using proper auth in backend as well to keep things simple)</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#75715e">// ... other imports
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">import</span> { <span style="color:#a6e22e">createConsumer</span> } <span style="color:#a6e22e">from</span> <span style="color:#e6db74">&#34;@rails/actioncable&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> { <span style="color:#a6e22e">WebsocketProvider</span> } <span style="color:#a6e22e">from</span> <span style="color:#e6db74">&#34;@y-rb/actioncable&#34;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">consumer</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">createConsumer</span>();
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">doc</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">Y</span>.<span style="color:#a6e22e">Doc</span>()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">provider</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">WebsocketProvider</span>(
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">doc</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">consumer</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;SyncChannel&#34;</span>,
</span></span><span style="display:flex;"><span>    {
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">id</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// ... other codes
</span></span></span></code></pre></div><p>You can see full frontend code in <a href="https://github.com/vikas-0/collab_demo/blob/main/app/javascript/App.jsx">App.jsx</a>. This contains everything in a single file which is not great but good enough for this case.</p>
<h3 id="step-4-set-up-rails-action-cable">Step 4: Set Up Rails Action Cable</h3>
<p>Create a new channel name <code>SyncChannel</code> at <code>app/channels/sync_channel.rb</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># frozen_string_literal: true</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SyncChannel</span> <span style="color:#f92672">&lt;</span> <span style="color:#66d9ef">ApplicationCable</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Channel</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">include</span> Y<span style="color:#f92672">::</span><span style="color:#66d9ef">Actioncable</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Sync</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">subscribed</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># initiate sync &amp; subscribe to updates, with optional persistence mechanism</span>
</span></span><span style="display:flex;"><span>    sync_for(session) { <span style="color:#f92672">|</span>id, update<span style="color:#f92672">|</span> save_doc(id, update) }
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">receive</span>(message)
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># broadcast update to all connected clients on all servers</span>
</span></span><span style="display:flex;"><span>    sync_to(session, message)
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">doc</span>
</span></span><span style="display:flex;"><span>    @doc <span style="color:#f92672">||=</span> load { <span style="color:#f92672">|</span>id<span style="color:#f92672">|</span> load_doc(id) }
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">private</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">session</span>
</span></span><span style="display:flex;"><span>    @session <span style="color:#f92672">||=</span> <span style="color:#66d9ef">Session</span><span style="color:#f92672">.</span>new(params<span style="color:#f92672">[</span><span style="color:#e6db74">:id</span><span style="color:#f92672">]</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">load_doc</span>(id)
</span></span><span style="display:flex;"><span>    data <span style="color:#f92672">=</span> <span style="color:#66d9ef">REDIS</span><span style="color:#f92672">.</span>get(id)
</span></span><span style="display:flex;"><span>    data <span style="color:#f92672">=</span> data<span style="color:#f92672">.</span>unpack(<span style="color:#e6db74">&#34;C*&#34;</span>) <span style="color:#66d9ef">unless</span> data<span style="color:#f92672">.</span>nil?
</span></span><span style="display:flex;"><span>    data
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">save_doc</span>(id, state)
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">REDIS</span><span style="color:#f92672">.</span>set(id, state<span style="color:#f92672">.</span>pack(<span style="color:#e6db74">&#34;C*&#34;</span>))
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span></code></pre></div><p>This has Redis initialized as REDIS, replace it with your Redis variable name. We also created a Session model for <code>sync_for</code> mehtod. You can check documentation for sync_for <a href="https://y-crdt.github.io/yrb-actioncable/Y/Actioncable/Sync.html#sync_for-instance_method">here</a>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#75715e"># frozen_string_literal: true</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Session</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">attr_reader</span> <span style="color:#e6db74">:id</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">initialize</span>(id)
</span></span><span style="display:flex;"><span>    @id <span style="color:#f92672">=</span> id
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">to_s</span>
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;sessions:</span><span style="color:#e6db74">#{</span>id<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span></code></pre></div><p>And finally <code>ApplicationCable::Connection</code> will be as follows</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#66d9ef">module</span> ApplicationCable
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Connection</span> <span style="color:#f92672">&lt;</span> <span style="color:#66d9ef">ActionCable</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Connection</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Base</span>
</span></span><span style="display:flex;"><span>    identified_by <span style="color:#e6db74">:id</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">connect</span>
</span></span><span style="display:flex;"><span>      self<span style="color:#f92672">.</span>id <span style="color:#f92672">=</span> <span style="color:#66d9ef">SecureRandom</span><span style="color:#f92672">.</span>uuid
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span></code></pre></div><h3 id="step-6-add-styles-for-collaboration-cursor-option">Step 6: Add Styles for Collaboration Cursor (Option)</h3>
<p>Everything should be working by now. In this step the cursor was looking odd, so some <a href="https://github.com/vikas-0/collab_demo/blob/main/app/javascript/App.css">CSS</a> can be add to make it look good.</p>
<p>Finally you can run your rails server and it should be good to go once we add all missing piecies specially authorisation.</p>
<h3 id="conclusion">Conclusion</h3>
<p>By following these steps, you should have a real-time collaborative editor up and running using Tiptap, Y.js, and Rails Action Cable. While we used Mantine for styling in this demo, you can customize the styling as per your requirements. This setup provides a robust foundation for building collaborative applications with rich text editing capabilities.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Seamless Remote Development with Any IDE Using Unison for Bidirectional SSH Sync</title>
      <link>https://www.geekyhub.in/post/seamless-remote-development-with-any-ide-using-unison-for-bidirectional-ssh-sync/</link>
      <pubDate>Sat, 15 Jun 2024 11:51:00 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/seamless-remote-development-with-any-ide-using-unison-for-bidirectional-ssh-sync/</guid>
      <description>SSH Development with Any Editor, Unison helps maintain a local copy and enables bidirectional sync, allowing you to use any tool, even Notepad, to edit your code efficiently.</description>
      <content:encoded><![CDATA[<p>If your development environment is on a remote server, you might need to code on the remote machine itself to see the effects of your changes in real time. This scenario is fairly common these days as applications become more complex, and setting up a local development environment requires extensive configuration or mocking of the resources used in the app.</p>
<p>In this case, you are left with very few options for code editors. Either you have to use CLI-based editors such as Vim, or you can use VSCode with the <a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh">Remote SSH extension</a>. Even with the extension, there are some issues related to code analysis and code completion. These processes have to happen on the remote machine, making your powerful local PC underutilized. And if you want to use Zed or Xcode, you are out of luck.</p>
<p>So, the solution is to have a local copy that is synced with the remote SSH directory. You can use several tools for this:</p>
<ul>
<li>
<p><strong>Rsync</strong>:</p>
<ul>
<li>Unidirectional sync, which might be fine for development as you will use the local machine&rsquo;s copy to manage changes on the SSH server.</li>
<li>Does not support file deletion.</li>
</ul>
</li>
<li>
<p><strong>SSHFS</strong>:</p>
<ul>
<li>Limited support on macOS.</li>
<li>Requires kernel changes, making it impractical for use on some machines.</li>
</ul>
</li>
<li>
<p><strong>Unison</strong>:</p>
<ul>
<li>Supports bidirectional sync.</li>
<li>Handles file deletions.</li>
<li>Fault-tolerant: even if the connection breaks, you can restart it, and it will continue syncing from the last known point.</li>
</ul>
</li>
</ul>
<p>This leaves Unison as the ideal choice for me.</p>
<p><a href="https://github.com/bcpierce00/unison">Unison</a> has fairly good documentation; you can go ahead and check their documents and explore on your own.</p>
<h1 id="installing-unison">Installing Unison</h1>
<p>You need to install Unison on both the host and remote machine. If you don&rsquo;t have sudo access on the remote machine, don&rsquo;t worry; you can download the binary and keep it anywhere.</p>
<ul>
<li>
<p><strong>Installing Unison on Mac local machine:</strong></p>
<ul>
<li><code>brew install unison</code></li>
<li><code>brew install autozimu/homebrew-formulas/unison-fsmonitor</code></li>
</ul>
</li>
<li>
<p>For Linux, you can follow the <a href="https://www.cis.upenn.edu/~bcpierce/unison/download/releases/stable/">official guide</a>.</p>
</li>
<li>
<p>Make sure to create a local folder to sync code from the remote machine.</p>
</li>
<li>
<p><strong>Run a test connection:</strong></p>
<ul>
<li>Example command: <code>unison -testServer ssh://user@remotehostname/path/to/folder /path/to/folder</code></li>
<li>If you get an error that Unison is not found on the remote server, specify the exact path to Unison using <code>-servercmd</code>. For example: <code>unison -testServer ssh://user@remotehostname/path/to/folder /path/to/folder -servercmd /home/path/to/unison/bin/unison</code>.</li>
</ul>
</li>
<li>
<p><strong>Final command for syncing:</strong></p>
<ul>
<li>Once the connection test is successful, start syncing with the final command:
<pre tabindex="0"><code>unison ssh://user@remotehostname/path/to/folder /path/to/folder -servercmd /home/path/to/unison/bin/unison -ignore &#34;BelowPath node_modules&#34; -ignore &#34;BelowPath .git&#34; -force newer -repeat watch
</code></pre></li>
<li>This command will sync all files and continue monitoring for further changes in the background while you develop. If you want to know the meaning of flags used here like <code>ignore</code>, <code>force</code> etc, you can check <a href="https://github.com/bcpierce00/unison/wiki">Unison user mannual</a>.</li>
</ul>
</li>
</ul>
<p>You can use any code editor to modify the local copy, and Unison will automatically sync the changes.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Stop using serverless-webpack for AWS Lambda</title>
      <link>https://www.geekyhub.in/post/using-esmodule-in-serverless-aws-lambda/</link>
      <pubDate>Thu, 06 Oct 2022 15:38:00 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/using-esmodule-in-serverless-aws-lambda/</guid>
      <description>AWS Lambda natively supports ES Module and top level await since node 14.x</description>
      <content:encoded><![CDATA[<p>I see that nodejs lambda projects are built using serverless and often include serverless-webpack. It is used to implement babel and get the latest javascript syntaxes, especially module and top-level awaits.</p>
<p>But as per this <a href="https://aws.amazon.com/about-aws/whats-new/2022/01/aws-lambda-es-modules-top-level-await-node-js-14/">blog post</a>, the AWS lambda environment already supports these features, so we should no longer need to use serverless-webpack.</p>
<p>There are some cons that I face while using webpack in serverless.</p>
<ol>
<li>Code is transpiled (and optionally minified), making it challenging to debug from logs, as line numbers and function names may not be the same per your development environment.</li>
<li>Using ESM only module is not straightforward. Such as node-fetch and d3, and the ESM-only module list is growing daily.</li>
<li>There could also be a performance impact as the code will be converted to commonJS, and this <a href="https://aws.amazon.com/blogs/compute/using-node-js-es-modules-and-top-level-await-in-aws-lambda/">benchmark test</a> shows that commonsJS could perform 43% worse than ESM.</li>
</ol>
<p>There are other benefits of babel and webpack besides transpiling to commonJS. But these are mostly catered towards browsers and not serverside usage.</p>
<p>How to use ESM in serverless? Just add <code>&quot;type&quot;: &quot;module&quot;</code> in <code>pacakge.json</code> in it will work in node 14.x and node 16.x.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Journey of building a game using the Flutter</title>
      <link>https://www.geekyhub.in/post/react-native-dev-learns-flutter/</link>
      <pubDate>Sat, 19 Feb 2022 09:17:00 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/react-native-dev-learns-flutter/</guid>
      <description>Learning Experience of flutter</description>
      <content:encoded><![CDATA[<p>For the last few weeks, I have been working on a React Native project for work. So this was my first experience writing &ldquo;real&rdquo; mobile apps. Before that, I only wrapped PWA&rsquo;s as APK and called myself a mobile developer 😎.</p>
<p>React-Native came naturally to me after climbing some learning curves as a React Developer. So, now I wanted to check out the buzz around Flutter.</p>
<p>So last weekend was a fine sunny day which is quite pleasing in the late winter season. It might not be winter from many people&rsquo;s standard. I opened the Flutter documentation getting started page. The installation file was quite big compared to react-native and it made my expectations high.</p>
<p>At this point, I knew nothing about dart and Flutter, how it works and how to write code. But the Flutter had an excellent <a href="https://docs.flutter.dev/get-started/flutter-for/react-native-devs">write-up</a> comparing React-Native to Dart and Flutter. It helped me directly dive into building things without learning anything. I got pumped up to create something; I thought of a real simple application/game that is just sorting a list of cities so that traversing through all cities in order will be optimal. It&rsquo;s not a fair game from the graphics standard, 😥 but good enough for me.</p>
<p>The app uses a list of cities downloaded from <a href="https://simplemaps.com/data/in-cities">simplemaps.com</a> and used a geometry formula to calculate the distance. After a day of playing out, I was able to finish it with the help of a lot of google, stack overflow, and 3rd party packages.</p>
<p>It almost feels like magic that I still don&rsquo;t know dart language correctly, but my app is running. Flutter dev tools are excellent compared to React-Native, which helped me identify and fix issues more quickly.</p>
<p>I published my app just for fun ☺️ on the <a href="https://play.google.com/store/apps/details?id=com.distoptim.geekyhub">PlayStore</a>, and if you are interested, you can also check out the <a href="https://github.com/vikas-0/Distoptim">code</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Animate SVG in React Native</title>
      <link>https://www.geekyhub.in/post/animate-svg-using-react-native-renanimated-2/</link>
      <pubDate>Sat, 05 Feb 2022 11:00:00 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/animate-svg-using-react-native-renanimated-2/</guid>
      <description>Animating SVG in React-Native using react-native-reanimated.</description>
      <content:encoded><![CDATA[<p>Here, by animating SVG, I mean to change the property of SVG elements dynamically, which will look live-like.</p>
<p>In react native, we can generate/render an SVG using the <a href="https://github.com/react-native-svg/react-native-svg">react-native-svg</a> library. A complex SVG comprises many more minor elements that could be animated individually. But here, for example, we will take only one piece, a circle.</p>
<p>The following code will draw a circle with a radius of 50 units.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-react" data-lang="react"><span style="display:flex;"><span>&lt;<span style="color:#f92672">Svg</span> <span style="color:#a6e22e">width</span><span style="color:#f92672">=</span>{<span style="color:#ae81ff">200</span>} <span style="color:#a6e22e">height</span><span style="color:#f92672">=</span>{<span style="color:#ae81ff">200</span>}&gt;
</span></span><span style="display:flex;"><span>  &lt;<span style="color:#f92672">Circle</span> <span style="color:#a6e22e">cx</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;55&#34;</span> <span style="color:#a6e22e">cy</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;55&#34;</span> <span style="color:#a6e22e">r</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;50&#34;</span> <span style="color:#a6e22e">stroke</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;black&#34;</span> <span style="color:#a6e22e">strokeWidth</span><span style="color:#f92672">=</span>{<span style="color:#ae81ff">5</span>} /&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">Svg</span>&gt;
</span></span></code></pre></div><p>Suppose we want to animate it to become large and small.
To achieve this, I will use <a href="https://docs.swmansion.com/react-native-reanimated/">React Native Reanimated</a>. To learn more about it, you can check out its documentation.</p>
<p>Logically, I am trying to increase or decrease the radius.</p>
<p>Since the radius value is a prop, I will use <code>useAnimatedProps</code>. But, first of all, convert Circle to an animated component.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-react" data-lang="react"><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">AnimatedCircle</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">Animated</span>.<span style="color:#a6e22e">createAnimatedComponent</span>(<span style="color:#a6e22e">Circle</span>);
</span></span></code></pre></div><p>Now, I can re-write component as</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-react" data-lang="react"><span style="display:flex;"><span>&lt;<span style="color:#f92672">Svg</span> <span style="color:#a6e22e">width</span><span style="color:#f92672">=</span>{<span style="color:#ae81ff">200</span>} <span style="color:#a6e22e">height</span><span style="color:#f92672">=</span>{<span style="color:#ae81ff">200</span>}&gt;
</span></span><span style="display:flex;"><span>  &lt;<span style="color:#f92672">AnimatedCircle</span> <span style="color:#a6e22e">cx</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;55&#34;</span> <span style="color:#a6e22e">cy</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;55&#34;</span> <span style="color:#a6e22e">r</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;50&#34;</span> <span style="color:#a6e22e">stroke</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;black&#34;</span> <span style="color:#a6e22e">strokeWidth</span><span style="color:#f92672">=</span>{<span style="color:#ae81ff">5</span>} /&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">Svg</span>&gt;
</span></span></code></pre></div><p>Next step is to store the stroke width and radius. width can be stored in a simple constat, but for the radius we will use <a href="https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/shared-values"><code>useSharedValue</code></a>, so that it can be used by woklet to animate.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-react" data-lang="react"><span style="display:flex;"><span><span style="color:#66d9ef">export</span> <span style="color:#66d9ef">default</span> ()=&gt;{
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">radius</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">useSharedValue</span>(<span style="color:#ae81ff">50</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">strokeWidth</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">5</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">return</span> (
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#f92672">Svg</span> <span style="color:#a6e22e">width</span><span style="color:#f92672">=</span>{<span style="color:#ae81ff">200</span>} <span style="color:#a6e22e">height</span><span style="color:#f92672">=</span>{<span style="color:#ae81ff">200</span>}&gt;
</span></span><span style="display:flex;"><span>      &lt;<span style="color:#f92672">AnimatedCircle</span>
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">cx</span><span style="color:#f92672">=</span>{<span style="color:#e6db74">`</span><span style="color:#e6db74">${</span><span style="color:#a6e22e">radius</span>.<span style="color:#a6e22e">value</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">strokeWidth</span><span style="color:#e6db74">}</span><span style="color:#e6db74">`</span>}
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">cy</span><span style="color:#f92672">=</span>{<span style="color:#e6db74">`</span><span style="color:#e6db74">${</span><span style="color:#a6e22e">radius</span>.<span style="color:#a6e22e">value</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">strokeWidth</span><span style="color:#e6db74">}</span><span style="color:#e6db74">`</span>}
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">r</span><span style="color:#f92672">=</span>{<span style="color:#e6db74">`</span><span style="color:#e6db74">${</span><span style="color:#a6e22e">radius</span>.<span style="color:#a6e22e">value</span><span style="color:#e6db74">}</span><span style="color:#e6db74">`</span>}
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">stroke</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;black&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">strokeWidth</span><span style="color:#f92672">=</span>{<span style="color:#a6e22e">strokeWidth</span>}
</span></span><span style="display:flex;"><span>      /&gt;
</span></span><span style="display:flex;"><span>    &lt;/<span style="color:#f92672">Svg</span>&gt;
</span></span><span style="display:flex;"><span>  )
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Here, I need some event or action to trigger the radius change. I&rsquo;ll use a button press. (withSpring is default provided animation which is not necessary to use but this looks cool 🤞)</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-react" data-lang="react"><span style="display:flex;"><span>&lt;<span style="color:#f92672">Button</span> <span style="color:#a6e22e">mode</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;contained&#34;</span> <span style="color:#a6e22e">onPress</span><span style="color:#f92672">=</span>{() =&gt; {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">if</span>(<span style="color:#a6e22e">radius</span>.<span style="color:#a6e22e">value</span> <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">80</span>) {
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">radius</span>.<span style="color:#a6e22e">value</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">withSpring</span>(<span style="color:#ae81ff">80</span>)
</span></span><span style="display:flex;"><span>  }<span style="color:#66d9ef">else</span>{
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">radius</span>.<span style="color:#a6e22e">value</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">withSpring</span>(<span style="color:#ae81ff">50</span>)
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}}&gt;
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">Press</span>
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">Button</span>&gt;
</span></span></code></pre></div><p>You&rsquo;ll notice that even after pressing the button, nothing happens. It is because change of sharedValue doesn&rsquo;t trigger re-render of the react component. finally animated props comes into the picture. Instead of passing prop directly, we will pass it using animated prop.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-react" data-lang="react"><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">animatedProps</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">useAnimatedProps</span>(() =&gt; ({
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">cx</span><span style="color:#f92672">:</span> <span style="color:#e6db74">`</span><span style="color:#e6db74">${</span><span style="color:#a6e22e">radius</span>.<span style="color:#a6e22e">value</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">strokeWidth</span><span style="color:#e6db74">}</span><span style="color:#e6db74">`</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">cy</span><span style="color:#f92672">:</span> <span style="color:#e6db74">`</span><span style="color:#e6db74">${</span><span style="color:#a6e22e">radius</span>.<span style="color:#a6e22e">value</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">strokeWidth</span><span style="color:#e6db74">}</span><span style="color:#e6db74">`</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">r</span><span style="color:#f92672">:</span><span style="color:#e6db74">`</span><span style="color:#e6db74">${</span><span style="color:#a6e22e">radius</span>.<span style="color:#a6e22e">value</span><span style="color:#e6db74">}</span><span style="color:#e6db74">`</span>
</span></span><span style="display:flex;"><span>}));
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-react" data-lang="react"><span style="display:flex;"><span>&lt;<span style="color:#f92672">Svg</span> <span style="color:#a6e22e">width</span><span style="color:#f92672">=</span>{<span style="color:#ae81ff">200</span>} <span style="color:#a6e22e">height</span><span style="color:#f92672">=</span>{<span style="color:#ae81ff">200</span>}&gt;
</span></span><span style="display:flex;"><span>  &lt;<span style="color:#f92672">AnimatedCircle</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">animatedProps</span><span style="color:#f92672">=</span>{<span style="color:#a6e22e">animatedProps</span>}
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">stroke</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;black&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">strokeWidth</span><span style="color:#f92672">=</span>{<span style="color:#a6e22e">strokeWidth</span>}
</span></span><span style="display:flex;"><span>  /&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">Svg</span>&gt;
</span></span></code></pre></div><p>Result, is something like this.
<figure>
    <img loading="lazy" src="circle-animation.gif" width="300px"/> 
</figure>
</p>
<p>This is a relatively simple example, but I hope I successfully demonstrated the possibilities.
Here is the <a href="https://gist.github.com/vikas-0/24c785c2a178a790b3b7352b400cc400">link</a> of complete code of the result if you are interested.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Handling multiple stores in a React-Redux application</title>
      <link>https://www.geekyhub.in/post/handling-multiple-stores-in-react-redux-application/</link>
      <pubDate>Tue, 12 Oct 2021 00:27:00 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/handling-multiple-stores-in-react-redux-application/</guid>
      <description>Using multiple store in a react application can get pretty complex.</description>
      <content:encoded><![CDATA[<p>In a react-redux application, it is a good practice to have only one redux store. But if for some weird/&ldquo;special&rdquo; reason if you have to have more than one store, you will face some problems.</p>
<p>The most common problem is that if we wrap a component with a provider and then wrap a child component with another provider, it&rsquo;s not easy to subscribe to the store of top-level provider.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-react" data-lang="react"><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">Component1</span> <span style="color:#f92672">=</span> () =&gt; {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">return</span> (
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#f92672">Provider</span> <span style="color:#a6e22e">store</span><span style="color:#f92672">=</span>{<span style="color:#a6e22e">store1</span>}&gt;
</span></span><span style="display:flex;"><span>      &lt;<span style="color:#f92672">Provider</span> <span style="color:#a6e22e">store</span><span style="color:#f92672">=</span>{<span style="color:#a6e22e">store2</span>}&gt;
</span></span><span style="display:flex;"><span>        &lt;<span style="color:#f92672">Component2</span> /&gt;
</span></span><span style="display:flex;"><span>      &lt;/<span style="color:#f92672">Provider</span>&gt;
</span></span><span style="display:flex;"><span>    &lt;/<span style="color:#f92672">Provider</span>&gt;
</span></span><span style="display:flex;"><span>  );
</span></span><span style="display:flex;"><span>};
</span></span></code></pre></div><p>It&rsquo;s so confusing that within a few iterations of development, you&rsquo;ll find yourself using providers on each component, and not being able to read values from both the stores in a single component will frustrate you.</p>
<p>To manage this elegantly, we can do some setup which will ease the things.</p>
<p>For this, we will need <code>react-redux 7</code> or greater. Because versions older than it doesn&rsquo;t use react&rsquo;s context API. And we will be using contexts to access multiple stores without wrapping with the providers again and again.</p>
<p>Create a context for each store. You can also import <code>ReactReduxContext</code> from <code>react-redux</code> and use it for one of the stores, which you want to make default.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-react" data-lang="react"><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">store1Context</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">React</span>.<span style="color:#a6e22e">createContext</span>();
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">store2Context</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">React</span>.<span style="color:#a6e22e">createContext</span>();
</span></span></code></pre></div><p>Now wrap the root component of the react application with a provider for each store, passing the contexts as props.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-react" data-lang="react"><span style="display:flex;"><span>&lt;<span style="color:#f92672">Provider</span> <span style="color:#a6e22e">store</span><span style="color:#f92672">=</span>{<span style="color:#a6e22e">store1</span>} <span style="color:#a6e22e">context</span><span style="color:#f92672">=</span>{<span style="color:#a6e22e">store1Context</span>}&gt;
</span></span><span style="display:flex;"><span>  &lt;<span style="color:#f92672">Provider</span> <span style="color:#a6e22e">store</span><span style="color:#f92672">=</span>{<span style="color:#a6e22e">store2</span>} <span style="color:#a6e22e">context</span><span style="color:#f92672">=</span>{<span style="color:#a6e22e">store2Context</span>}&gt;
</span></span><span style="display:flex;"><span>    &lt;<span style="color:#f92672">App</span>/&gt;
</span></span><span style="display:flex;"><span>  &lt;/<span style="color:#f92672">Provider</span>&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">Provider</span>&gt;
</span></span></code></pre></div><p>We also need to create custom dispatch and selector hooks. If you use the default hooks (<code>useSelector</code>, <code>useDispatch</code>), it will use the store with default context, if any.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-react" data-lang="react"><span style="display:flex;"><span><span style="color:#66d9ef">export</span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">useStore1Dispatch</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">createDispatchHook</span>(<span style="color:#a6e22e">store1Context</span>);
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">export</span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">useStore1Selector</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">createSelectorHook</span>(<span style="color:#a6e22e">store1Context</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">export</span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">useStore2Dispatch</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">createDispatchHook</span>(<span style="color:#a6e22e">store2Context</span>);
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">export</span> <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">useStore2Selector</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">createSelectorHook</span>(<span style="color:#a6e22e">store2Context</span>);
</span></span></code></pre></div><p>From further development, you can use these custom selector and dispatch hooks to use the preferred store in any of the components throughout the application.</p>
<p>If you prefer to connect HOC, then you can do</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-react" data-lang="react"><span style="display:flex;"><span><span style="color:#a6e22e">connect</span>(<span style="color:#a6e22e">mapStateToProps</span>, <span style="color:#a6e22e">mapDispatchtoProps</span>,<span style="color:#a6e22e">mergeProps</span>, {<span style="color:#a6e22e">context</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">store1Context</span>})(<span style="color:#a6e22e">Component</span>) 
</span></span></code></pre></div><p>Let me know if you have any suggestions or questions. Thanks</p>
]]></content:encoded>
    </item>
    <item>
      <title>Difference between &#39;useEffect&#39; and calling function directly inside a component.</title>
      <link>https://www.geekyhub.in/post/difference-between-useeffect-and-direct-function-call/</link>
      <pubDate>Sun, 09 May 2021 18:02:00 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/difference-between-useeffect-and-direct-function-call/</guid>
      <description>Finding out the difference between &amp;#39;useEffect&amp;#39; without dependency array and executing function directly.</description>
      <content:encoded><![CDATA[<p>In React, the useEffect hook is pretty straightforward. But its simplicity sometimes makes me forget its actual function. I remembered useEffect simply as something which takes a callback and a dependency array as arguments, and it will execute the callback whenever the dependency array is changed. And in case of no dependency array, it will run the callback each time the component renders.</p>
<p>But then what will be the difference between the following two cases.
<figure>
    <img loading="lazy" src="useeffect.svg"
         alt="useEffect vs function call"/> 
</figure>
</p>
<p>To find out, I have created a small React application with a couple of props and states of type number and four buttons to increment those numbers.</p>
<blockquote>
<p><code>App.js</code></p></blockquote>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
<table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#66d9ef">import</span> { <span style="color:#a6e22e">useState</span> } <span style="color:#a6e22e">from</span> <span style="color:#e6db74">&#39;react&#39;</span>;
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> <span style="color:#a6e22e">TestComponent</span> <span style="color:#a6e22e">from</span> <span style="color:#e6db74">&#39;./TestComponent&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">App</span>() {
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">const</span> [<span style="color:#a6e22e">prop1</span>, <span style="color:#a6e22e">setProp1</span>] <span style="color:#f92672">=</span> <span style="color:#a6e22e">useState</span>(<span style="color:#ae81ff">0</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">const</span> [<span style="color:#a6e22e">prop2</span>, <span style="color:#a6e22e">setProp2</span>] <span style="color:#f92672">=</span> <span style="color:#a6e22e">useState</span>(<span style="color:#ae81ff">0</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">return</span> (
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;</span><span style="color:#a6e22e">div</span><span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&lt;</span><span style="color:#a6e22e">button</span> <span style="color:#a6e22e">onClick</span><span style="color:#f92672">=</span>{()=&gt;<span style="color:#a6e22e">setProp1</span>(<span style="color:#a6e22e">prev</span>=&gt; <span style="color:#a6e22e">prev</span><span style="color:#f92672">+</span><span style="color:#ae81ff">1</span>)}<span style="color:#f92672">&gt;</span><span style="color:#a6e22e">Prop</span> <span style="color:#ae81ff">1</span><span style="color:#f92672">&lt;</span><span style="color:#960050;background-color:#1e0010">/button&gt;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&lt;</span><span style="color:#a6e22e">button</span> <span style="color:#a6e22e">onClick</span><span style="color:#f92672">=</span>{()=&gt;<span style="color:#a6e22e">setProp2</span>(<span style="color:#a6e22e">prev</span>=&gt; <span style="color:#a6e22e">prev</span><span style="color:#f92672">+</span><span style="color:#ae81ff">1</span>)}<span style="color:#f92672">&gt;</span><span style="color:#a6e22e">Prop</span> <span style="color:#ae81ff">2</span><span style="color:#f92672">&lt;</span><span style="color:#960050;background-color:#1e0010">/button&gt;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&lt;</span><span style="color:#a6e22e">TestComponent</span> <span style="color:#a6e22e">prop1</span><span style="color:#f92672">=</span>{<span style="color:#a6e22e">prop1</span>} <span style="color:#a6e22e">prop2</span><span style="color:#f92672">=</span>{<span style="color:#a6e22e">prop2</span>}<span style="color:#f92672">/&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;</span><span style="color:#960050;background-color:#1e0010">/div&gt;</span>
</span></span><span style="display:flex;"><span>  );
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">export</span> <span style="color:#66d9ef">default</span> <span style="color:#a6e22e">App</span>;
</span></span></code></pre></td></tr></table>
</div>
</div><blockquote>
<p><code>TestComponent.js</code></p></blockquote>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
<table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">26
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">27
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">28
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#66d9ef">import</span> { <span style="color:#a6e22e">useEffect</span>, <span style="color:#a6e22e">useState</span> } <span style="color:#a6e22e">from</span> <span style="color:#e6db74">&#39;react&#39;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">TestComponent</span>({<span style="color:#a6e22e">prop1</span>, <span style="color:#a6e22e">prop2</span>}) {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">const</span> [<span style="color:#a6e22e">state1</span>, <span style="color:#a6e22e">setState1</span>] <span style="color:#f92672">=</span> <span style="color:#a6e22e">useState</span>(<span style="color:#ae81ff">0</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">const</span> [<span style="color:#a6e22e">state2</span>, <span style="color:#a6e22e">setState2</span>] <span style="color:#f92672">=</span> <span style="color:#a6e22e">useState</span>(<span style="color:#ae81ff">0</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">useEffect</span>(()=&gt;{
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">log</span>(<span style="color:#e6db74">&#39;rendered - useEffect&#39;</span>, <span style="color:#a6e22e">state1</span>, <span style="color:#a6e22e">state2</span>, <span style="color:#a6e22e">prop1</span>, <span style="color:#a6e22e">prop2</span>);
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">someImportantWork</span> <span style="color:#f92672">=</span> ()=&gt;{
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">log</span>(<span style="color:#e6db74">&#39;rendered - functionCall&#39;</span>, <span style="color:#a6e22e">state1</span>, <span style="color:#a6e22e">state2</span>, <span style="color:#a6e22e">prop1</span>, <span style="color:#a6e22e">prop2</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">someImportantWork</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> (
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&lt;</span><span style="color:#a6e22e">div</span><span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;</span><span style="color:#a6e22e">button</span> <span style="color:#a6e22e">onClick</span><span style="color:#f92672">=</span>{()=&gt;<span style="color:#a6e22e">setState1</span>(<span style="color:#a6e22e">prev</span>=&gt; <span style="color:#a6e22e">prev</span><span style="color:#f92672">+</span><span style="color:#ae81ff">1</span>)}<span style="color:#f92672">&gt;</span><span style="color:#a6e22e">State</span> <span style="color:#ae81ff">1</span><span style="color:#f92672">&lt;</span><span style="color:#960050;background-color:#1e0010">/button&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;</span><span style="color:#a6e22e">button</span> <span style="color:#a6e22e">onClick</span><span style="color:#f92672">=</span>{()=&gt;<span style="color:#a6e22e">setState2</span>(<span style="color:#a6e22e">prev</span>=&gt; <span style="color:#a6e22e">prev</span><span style="color:#f92672">+</span><span style="color:#ae81ff">1</span>)}<span style="color:#f92672">&gt;</span><span style="color:#a6e22e">State</span> <span style="color:#ae81ff">2</span><span style="color:#f92672">&lt;</span><span style="color:#960050;background-color:#1e0010">/button&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;</span><span style="color:#a6e22e">p</span><span style="color:#f92672">&gt;</span><span style="color:#a6e22e">Prop</span> <span style="color:#ae81ff">1</span><span style="color:#f92672">:</span> {<span style="color:#a6e22e">prop1</span>}<span style="color:#f92672">&lt;</span><span style="color:#960050;background-color:#1e0010">/p&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;</span><span style="color:#a6e22e">p</span><span style="color:#f92672">&gt;</span><span style="color:#a6e22e">Prop</span> <span style="color:#ae81ff">2</span><span style="color:#f92672">:</span> {<span style="color:#a6e22e">prop2</span>}<span style="color:#f92672">&lt;</span><span style="color:#960050;background-color:#1e0010">/p&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;</span><span style="color:#a6e22e">p</span><span style="color:#f92672">&gt;</span><span style="color:#a6e22e">State</span> <span style="color:#ae81ff">1</span><span style="color:#f92672">:</span> {<span style="color:#a6e22e">state1</span>}<span style="color:#f92672">&lt;</span><span style="color:#960050;background-color:#1e0010">/p&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;</span><span style="color:#a6e22e">p</span><span style="color:#f92672">&gt;</span><span style="color:#a6e22e">State</span> <span style="color:#ae81ff">2</span><span style="color:#f92672">:</span> {<span style="color:#a6e22e">state2</span>}<span style="color:#f92672">&lt;</span><span style="color:#960050;background-color:#1e0010">/p&gt;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&lt;</span><span style="color:#960050;background-color:#1e0010">/div&gt;</span>
</span></span><span style="display:flex;"><span>    );
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">export</span> <span style="color:#66d9ef">default</span> <span style="color:#a6e22e">TestComponent</span>;
</span></span></code></pre></td></tr></table>
</div>
</div><p>We can see in following that both <code>console.log</code> statement runs whenever we update <code>state</code> or <code>prop</code>.</p>
<video controls preload="auto" width="100%"  loop playsinline class="html-video">
        <source src="/post/difference-between-useeffect-and-direct-function-call/withoutdelay.mp4" type="video/mp4" }}>
      <p></p>
    </video>
<p>But I think we are missing something because both seems to be same. So let&rsquo;s slow down the rendering.</p>
<p>To slow down the rendering I added a very long loopin inside <code>return</code>.</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
<table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#66d9ef">import</span> { <span style="color:#a6e22e">useEffect</span>, <span style="color:#a6e22e">useState</span> } <span style="color:#a6e22e">from</span> <span style="color:#e6db74">&#39;react&#39;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">x</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Array(<span style="color:#ae81ff">10999999</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">TestComponent</span>({<span style="color:#a6e22e">prop1</span>, <span style="color:#a6e22e">prop2</span>}) {
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
<table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> (
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&lt;</span><span style="color:#a6e22e">div</span><span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;</span><span style="color:#a6e22e">button</span> <span style="color:#a6e22e">onClick</span><span style="color:#f92672">=</span>{()=&gt;<span style="color:#a6e22e">setState1</span>(<span style="color:#a6e22e">prev</span>=&gt; <span style="color:#a6e22e">prev</span><span style="color:#f92672">+</span><span style="color:#ae81ff">1</span>)}<span style="color:#f92672">&gt;</span><span style="color:#a6e22e">State</span> <span style="color:#ae81ff">1</span><span style="color:#f92672">&lt;</span><span style="color:#960050;background-color:#1e0010">/button&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;</span><span style="color:#a6e22e">button</span> <span style="color:#a6e22e">onClick</span><span style="color:#f92672">=</span>{()=&gt;<span style="color:#a6e22e">setState2</span>(<span style="color:#a6e22e">prev</span>=&gt; <span style="color:#a6e22e">prev</span><span style="color:#f92672">+</span><span style="color:#ae81ff">1</span>)}<span style="color:#f92672">&gt;</span><span style="color:#a6e22e">State</span> <span style="color:#ae81ff">2</span><span style="color:#f92672">&lt;</span><span style="color:#960050;background-color:#1e0010">/button&gt;</span>
</span></span><span style="display:flex;"><span>        {<span style="color:#a6e22e">x</span>.<span style="color:#a6e22e">map</span>(<span style="color:#a6e22e">i</span>=&gt; <span style="color:#66d9ef">null</span>)}
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;</span><span style="color:#a6e22e">p</span><span style="color:#f92672">&gt;</span><span style="color:#a6e22e">Prop</span> <span style="color:#ae81ff">1</span><span style="color:#f92672">:</span> {<span style="color:#a6e22e">prop1</span>}<span style="color:#f92672">&lt;</span><span style="color:#960050;background-color:#1e0010">/p&gt;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>After the delay we can clearly see that expression inside useEffect is always excuted after expression in the fucntion.</p>
<video controls preload="auto" width="100%"  loop playsinline class="html-video">
        <source src="/post/difference-between-useeffect-and-direct-function-call/withdelay.mp4" type="video/mp4" }}>
      <p></p>
    </video>
<p>It is because the definition of <code>useEffect</code> stated at the beginning of this post is incomplete. useEffect not only executes the callback on each render (depending upon the dependency array) but also ensures that rendering has been completed. That&rsquo;s why useEffect&rsquo;s <code>console.log</code> is delayed.</p>
<p>This should not be a problem if you are doing some small calculation or, as in this example, logging. But if you are using <code>ref</code> to access the element, you must ensure that render has happened; else, you may get the wrong reference.</p>
]]></content:encoded>
    </item>
    <item>
      <title>How to use OneSignal with ReactJs</title>
      <link>https://www.geekyhub.in/post/using-one-signal-with-react-js/</link>
      <pubDate>Sat, 09 Jan 2021 18:16:00 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/using-one-signal-with-react-js/</guid>
      <description>Exploring the possiblity to use OneSignal with ReactJs with existing service worker</description>
      <content:encoded><![CDATA[<p>Using OneSignal with react is fairly easy if one doesn&rsquo;t care about existing service-worker. But if there is an existing service worker, things may not work as is expected.</p>
<p>First, we will create a react app with a service-worker.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>npx create-react-app my-app --template pwa
</span></span></code></pre></div><p>This should create a folder named <code>'my-app'</code> containing all the app-related files. To check everything is fine, we can run the following commands, and a browser tab should open with the ReactJs logo.
<figure>
    <img loading="lazy" src="cra-app-homepage.png"/> 
</figure>
</p>
<p>Now we will enable the default service worker.</p>
<p>In <code>src/index.js</code> change <code>unregister()</code> to <code>register()</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#75715e">// serviceWorkerRegistration.unregister();
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">serviceWorkerRegistration</span>.<span style="color:#a6e22e">register</span>();
</span></span></code></pre></div><p>Let us add some code in the service worker (<code>src/service-worker.js</code>) to send a test push message from Chrome DevTools.</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
<table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">72
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">73
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">74
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">75
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">76
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#75715e">// Any other custom service worker logic can go here.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">self</span>.<span style="color:#a6e22e">addEventListener</span>(<span style="color:#e6db74">&#39;push&#39;</span>, (<span style="color:#a6e22e">event</span>) =&gt; {
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">log</span>(<span style="color:#a6e22e">event</span>.<span style="color:#a6e22e">data</span>);
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></td></tr></table>
</div>
</div><p>But wait! the service worker will not run in the dev server by default. We can change this behavior, but it&rsquo;s not recommended to do so. It should be built first and then served. To serve, we need need to install a static file server such as <code>serve</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>npm install -g serve
</span></span></code></pre></div><p>Then build and serve by running following commands form <code>my-app</code> folder.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>npm run build
</span></span><span style="display:flex;"><span>serve -s build
</span></span></code></pre></div><figure>
    <img loading="lazy" src="chromedevtool.png" width="500px"/> <figcaption>
            We can see that the worker is loaded, and the test push message object is logged in the console.
        </figcaption>
</figure>

<h2 id="onesignal-integration">OneSignal Integration</h2>
<p>The first few steps are pretty straightforward. Create an OneSignal account, then create a new website and choose custom code and fill site setup form as shown <em>(Assuming we will be serving on port 5000)</em>.
<figure>
    <img loading="lazy" src="onesignal-setting.png"/> 
</figure>
</p>
<p>Post this step; we&rsquo;ll get a zip file (Web SDK) containing service workers to download. We&rsquo;ll have extract files <code>OneSignalSDKWorker.js</code> , <code>OneSignalSDKUpdaterWorker.js</code> and put them inside the public folder.</p>
<p>And then finally we&rsquo;ll get the custom code.
<figure>
    <img loading="lazy" src="onesignalcustomcode.png"/> 
</figure>
</p>
<p>The first script tag will be placed in <code>public/index.html</code>.</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
<table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">39
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">40
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">41
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>    &lt;<span style="color:#f92672">script</span> <span style="color:#a6e22e">src</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;https://cdn.onesignal.com/sdks/OneSignalSDK.js&#34;</span> <span style="color:#a6e22e">async</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;&#34;</span>&gt;&lt;/<span style="color:#f92672">script</span>&gt;
</span></span><span style="display:flex;"><span>  &lt;/<span style="color:#f92672">body</span>&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">html</span>&gt;
</span></span></code></pre></td></tr></table>
</div>
</div><p>Second script tag can be put into at the end <code>index.js</code> after few modification for this demo.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>window.<span style="color:#a6e22e">OneSignal</span> <span style="color:#f92672">=</span> window.<span style="color:#a6e22e">OneSignal</span> <span style="color:#f92672">||</span> [];
</span></span><span style="display:flex;"><span>window.<span style="color:#a6e22e">OneSignal</span>.<span style="color:#a6e22e">push</span>(<span style="color:#66d9ef">function</span>() {
</span></span><span style="display:flex;"><span>  window.<span style="color:#a6e22e">OneSignal</span>.<span style="color:#a6e22e">init</span>({
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">appId</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;eb29dedd-4af2-4fa8-b73a-39bc2e7cc6d5&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">notifyButton</span><span style="color:#f92672">:</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">enable</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>    },
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">allowLocalhostAsSecureOrigin</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>  });
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div><p>Two more steps are necessary as, OneSignal service-worker will replace the existing service-worker.</p>
<ol>
<li>We will make OneSignal Service worker as default service-worker by updating path in <code>serviceWorkerRegistration.js</code></li>
</ol>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>window.<span style="color:#a6e22e">addEventListener</span>(<span style="color:#e6db74">&#39;load&#39;</span>, () =&gt; {
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">// const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">swUrl</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">`</span><span style="color:#e6db74">${</span><span style="color:#a6e22e">process</span>.<span style="color:#a6e22e">env</span>.<span style="color:#a6e22e">PUBLIC_URL</span><span style="color:#e6db74">}</span><span style="color:#e6db74">/OneSignalSDKWorker.js`</span>;
</span></span></code></pre></div><ol start="2">
<li>We&rsquo;ll append <code>importScripts('/service-worker.js');</code> in <code>OneSignalSDKWorker.js</code> and <code>OneSignalSDKUpdaterWorker.js</code>, so that our existing service worker can still be loaded.</li>
</ol>
<p>Now a bell icon will appear at bottom right and clicing on that will intiate subscribe option. Things can be tested through OneSignal dashboard.
<figure>
    <img loading="lazy" src="test-notification.png"/> 
</figure>
</p>
<p>Now the OneSignal worker will be able to show notification, as well as the existing service worker will also log the object in console.</p>
<p>This is probably not the most elegant way and there is obviously scope of improvment in this approach so feel free to comment.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Public VPN is not what&#39;s it advertised as</title>
      <link>https://www.geekyhub.in/post/truth-about-vpn-services/</link>
      <pubDate>Sat, 19 Dec 2020 20:39:48 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/truth-about-vpn-services/</guid>
      <description>There are now a lot of myths and misinformation about it is floating in the market.</description>
      <content:encoded><![CDATA[<p>In the last few years, there has been a flow of public VPN services in the market. But there are now a lot of myths and misinformation about it is floating in the market.</p>
<p>Sadly, this misinformation is being propagated by the company itself and knowing unknowingly by tech YouTubers who frequently gets sponsored by the Public Providers.</p>
<p>Here I am listing a few of the things these services can offer and some which these can&rsquo;t</p>
<h2 id="privacy">Privacy</h2>
<p>Often a VPN is touted as a one-stop for all your digital privacy goals. But in my opinion, when you think of privacy, you should also ask privacy from whom. From your ISP? Yes. From your National Security agencies? Maybe not.</p>
<p>Privacy is more of a practice than a product. Suppose you open your personal social and email accounts over a VPN network and the same on your local network. In that case, it can be easily tracked that both IPs belong to the same person. Also, your VPN provider will always know your real IP address. So in case some could hack, buy, or force them to hand over the data, it is out with all of your browsing histories.</p>
<p>Often VPN providers claim to have a no-log policy, but you just have to believe their words until something happens.</p>
<h2 id="internet-speed">Internet Speed</h2>
<p>This claim is somewhat valid but not wholly. In a sporadic case, your local ISP has very bad routing, which causes many bad hops. In that case, a VPN can help improve your internet browsing experience. But, In the vast majority of cases, you are expected to get a hit on internet speed in lieu of some degree of privacy.</p>
<h2 id="wide-variety-of-content-access">Wide variety of content access</h2>
<p>This is the most common use case of a public VPN service. You want to watch a youtube video or Netflix show that isn&rsquo;t available in your location. You can easily circumvent it. Also, it is helpful for those who people live out of the country for business purposes. But, when they leave, they lose access to many local online services that they may want to use while abroad, such as Hotstar, which broadcasts most Indian sports at affordable rates. But, you can&rsquo;t access it while being abroad usually.</p>
<h2 id="final-thoughts">Final Thoughts</h2>
<p>It&rsquo;s good to have one, but you should know what you have.</p>
]]></content:encoded>
    </item>
    <item>
      <title>How to create UPI Payment link in HTML</title>
      <link>https://www.geekyhub.in/post/create-upi-link-recognized-url-scheme-html/</link>
      <pubDate>Fri, 06 Nov 2020 08:25:00 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/create-upi-link-recognized-url-scheme-html/</guid>
      <description>Creating UPI link in HTML</description>
      <content:encoded><![CDATA[<p><strong>TLDR</strong> - The URL scheme is <em>upi://pay?pn=&lt;Name&gt;&amp;pa=&lt;UPI ID&gt;&amp;cu=&lt;Currency Code&gt;</em></p>
<p>All UPI apps support this custom URL scheme, but many don&rsquo;t seem to be using it. When you click this type of link when you click, the &lsquo;Open With&rsquo; menu will appear with a list of all the UPI applications on your phone. If you are on mobile device you can try link <a href="#ZgotmplZ">upi://pay?pn=Vikas%20Kumar&amp;pa=vikaskr@freecharge&amp;cu=INR</a>, it should redirect to an UPI app</p>
<figure>
    <img loading="lazy" src="/images/upi_custom_url_scheme.png"/> <figcaption>
            UPI URL Scheme in Acion
        </figcaption>
</figure>

<p>Although this link will not work on your computer, you can solve it with the help of media query and replace it with a QR code. Or you can use javascript to detect if the URL scheme is supported or not, but as far as I tried, it didn&rsquo;t seem reliable to me.</p>]]></content:encoded>
    </item>
    <item>
      <title>Taking a look at Modern alternatives for Microsoft Notepad</title>
      <link>https://www.geekyhub.in/post/alternative-for-mircrosoft-notepad/</link>
      <pubDate>Mon, 29 Jun 2020 13:19:00 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/alternative-for-mircrosoft-notepad/</guid>
      <description>Windows Notepad alternatives with Fluent Design</description>
      <content:encoded><![CDATA[<p>Notepad has been an excellent lightweight tool since the beginning of Windows. But lately, it isn&rsquo;t changing much with the new fluent design language of Windows 10. However, there are some excellent third-party alternatives to Notepad. Since the version 2004 (May 2020 Update) of Windows 10, now we can uninstall Notepad easily. So you can get rid of Notepad altogether if you are satisfied with following 3rd party alternatives. :-</p>
<ol>
<li>
<p><strong>Notepads</strong> <figure>
    <img loading="lazy" src="/images/notepads_uwp_app.png"/> <figcaption>
            Notepads App
        </figcaption>
</figure>
 <a href="https://www.notepadsapp.com/">Notepads</a> is yet another opensource alternative to Notepad with fluent design and tabbed view. Even their <a href="https://github.com/JasonStein/Notepads">GitHub</a> page says that their motivation behind this that they have been waiting long before modern Notepad to be released before he decided to do it by himself. <figure><a href="https://www.microsoft.com/store/productId/9NHL4NSC67WM">
    <img loading="lazy" src="/images/English_get-it-from-MS.png" width="200px"/> </a>
</figure>
</p>
</li>
<li>
<p><strong>Quick Pad</strong> - is also open source and comes with the fluent design. QuickPad is closer to Microsoft Notepad as there are no tabs and have classic menubar. There are some extra features though, <figure>
    <img loading="lazy" src="/images/quick_pad_compact_mode.png"/> <figcaption>
            Quick Pad in compact overlay mode
        </figcaption>
</figure>
like focus mode which removes all the extra options from the screen and compact overlay mode switches it to something like a sticky note. <figure><a href="https://www.microsoft.com/store/productId/9PDLWQHTLSV3">
    <img loading="lazy" src="/images/English_get-it-from-MS.png" width="200px"/> </a>
</figure>
</p>
</li>
</ol>
<h2 id="which-one-do-i-use">Which one do I use?</h2>
<p>I use Notepads, just for its tabbed interface. Otherwise, I don&rsquo;t have anything to dislike in QuickPad too.</p>
<h2 id="what-i-dont-like">What I don&rsquo;t Like?</h2>
<p>There is one problem with both of the apps. If you use the hibernate feature or your laptop is set to hibernate after a few minutes of sleep, then while resuming, your previously running instance of app will not resume. This means any unsaved text is lost and that doesn&rsquo;t happen for Win32 apps like Notepad or Notepad++. I think this has something to do with UWP app architecture because the same is happening for Windows Calculator. I hope it is fixed or they&rsquo;ll be able to find a workaround.
Till then always remember to save the file before leaving your PC unattended or disable the hibernate feature.</p>
<p>There are some other problems though such as not able to write to system folders, unable to handle large file. But don&rsquo;t hamper me in day to day usage because I don&rsquo;t use it for more advance text editing. For me it is simply Notepad replacement which anyway I wasn&rsquo;t using for anything complex.</p>]]></content:encoded>
    </item>
    <item>
      <title>WSL and Visual Studio Code is making Windows better</title>
      <link>https://www.geekyhub.in/post/wsl-vscode-making-windows-better/</link>
      <pubDate>Mon, 17 Feb 2020 01:48:59 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/wsl-vscode-making-windows-better/</guid>
      <description>There are some new updates in WSL which is finally making Windows worthy of Developers</description>
      <content:encoded><![CDATA[<p>Many developers would agree that Windows is not known to be developer-friendly until you aren’t developing for the Windows ecosystem. Linux distros, on the other hand, are very good for development especially adding the fact that most of your build is going to run on Linux based servers.</p>
<h2 id="microsoft-is-continuously-trying-to-fix-it">Microsoft is continuously trying to fix it</h2>
<p>They are continuously improving PowerShell, launched new Windows Terminal but they still can’t match the swiftness and community support of developing on Linux box. To pull around this issue, they have WSL.</p>
<p>In my previous post <a href="https://www.geekyhub.in/post/problems-with-windows-subsystem-for-linux/">&ldquo;Windows subsystem for Linux is of any use?&rdquo;</a>, I heavily criticizes how it is unusable due to the lack of any GUI editor respecting it. But on the 3rd of May 2019, it changed. Microsoft released the <a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack">Remote Development extension</a> for the Visual Studio Code. Now all the flaws I stated in my previous article are invalid (it still has some flaws but it is at an acceptable level).</p>
<blockquote>
<p><strong>Note</strong>: JetBrains IDE also claims to support this, but I am yet to test it. My
whole workflow is now in VS Code.</p></blockquote>
<p>With this extension installed, now I can just type <em>&ldquo;code .&rdquo;</em> in Ubuntu terminal and VScode code will launch with WSL connected to it, so there are no configs to do.
<figure>
    <img loading="lazy" src="/images/ubuntuWSL.png"/> <figcaption>
            Ubuntu on WSL
        </figcaption>
</figure>

The terminal will be bash and by default, it will use git installed in ubuntu, will run language support and linters from binaries installed in ubuntu. There still may need to reinstall some extensions in remote mode, but you don’t have to figure it out. VS Code will automatically prompt you and can be done by a single click. With all this, there is WS2 around the corner which is supposed to improve remote development.
<figure>
    <img loading="lazy" src="/images/vscodeonremotewsl.png"/> <figcaption>
            VisualStudio Code running with Remote Development for WSL
        </figcaption>
</figure>
</p>
<h2 id="now-the-question-remains">Now the question remains.</h2>
<p>That if Linux is better for development then why don’t we use a Linux distro. That will be the right approach and easier for beginners. I’ll still recommend new developers to avoid this and use a Linux distro. But this approach is really helpful for those who use some software that doesn’t have good Linux counterpart or simply the hardware they are using is not well supported in Linux.</p>]]></content:encoded>
    </item>
    <item>
      <title>Windows subsystem for Linux is of any use?</title>
      <link>https://www.geekyhub.in/post/problems-with-windows-subsystem-for-linux/</link>
      <pubDate>Thu, 21 Mar 2019 02:25:59 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/problems-with-windows-subsystem-for-linux/</guid>
      <description>Problems With Windows Subsystem for Linux</description>
      <content:encoded><![CDATA[<p>I was a long term user of Arch Linux. But recently I decided to switch to  Windows. Why? Because I needed to do some media editing and I heard about WSL which promises a more comfortable life for developers on Windows.</p>
<h2 id="installation">Installation</h2>
<p>So I installed a new SSD and started my Windows 10 installation process. Installation went smooth. Then I opened PowerShell to activate the feature and downloaded Ubuntu from the Windows Store.
Finally, I launched bash and installed <em>git</em>, <em>nodejs</em>, <em>npm</em>, <em>yarn</em>, <em>python</em>, <em>pip</em>. I was excited to try it all out on Microsoft own Visual Studio Code as it is the only editor which officially supports WSL.</p>
<h2 id="git">GIT</h2>
<p>My first bummer was GIT. VSCode refused to detect git installation on Ubuntu. I googled many workarounds and none of those worked. So now I have the dual setup of GIT, one Windows version and one Ubuntu version.</p>
<h2 id="nodejs">NodeJS</h2>
<p>Next step was node development. VSCode&rsquo;s intellisense worked for NodeJs, but this feature doesn&rsquo;t require a node setup in this editor. I tried debugging which also worked flawlessly as I just had to as a parameter in the launch.json file to use WSL. The real problem started when I decided to use ESlint plugin. The editor couldn&rsquo;t find the files. The only working solution was to directly access the Linux file system which is strongly advised in WSL documentation to avoid. So now I have a dual setup of NodeJS.</p>
<h2 id="python">Python</h2>
<p>Python had no perks of the JavaScript. Even for intellisense, I had to go for native installation.</p>
<h2 id="ssh">SSH</h2>
<p>Finally, I gave up on VScode integration and thought it would be useful for SSHing to my EC2 instances because everybody know how painful to do that in Windows through Putty. But file permissions on Windows didn&rsquo;t let me do even this. Console presented me a message <em>&quot; WARNING: UNPROTECTED PRIVATE KEY FILE!&quot;</em>. Then I got to know that I can&rsquo;t set file permissions too as it uses Windows file system. Now I have a separate Putty configuration to connect to EC2.</p>
<p>So my conclusion is that Microsoft&rsquo;s claim that the development environment which feels like home is a failure. What is your opinion?</p>]]></content:encoded>
    </item>
    <item>
      <title>Prevent roommates/family members from unlocking your android phone with your fingerprint while you are asleep</title>
      <link>https://www.geekyhub.in/post/prevent-disable-fingerprint-unlock-temporarily/</link>
      <pubDate>Wed, 13 Jun 2018 01:25:00 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/prevent-disable-fingerprint-unlock-temporarily/</guid>
      <description>How to disable biometric unlocking of your Android device temporarily</description>
      <content:encoded><![CDATA[<figure>
    <img loading="lazy" src="/images/fingerprintunlock.jpg"/> 
</figure>

<p>Today fingerprint scanners are on almost every phone. It is very handy to have a fingerprint sensor to unlock your device. By the time you pull out a phone from your pocket to your eyes it is already unlocked. It also prevents snooping of your password or pattern from behind your shoulders or through a security camera.</p>
<p>But one place where it fails to hide your sensitive chats and photos from your sneaky roommates or a nosy family member. They can easily use your finger to unlock your phone while you are asleep or too high.</p>
<h2 id="so-how-to-prevent-this">So how to prevent this?</h2>
<p>Simply, by forcing the phone to ask for the PIN when needed. One simple way is to restart your phone before sleeping because after restarting your phone asks for a PIN and will not accept your fingerprint for first unlock.</p>
<p>But it&rsquo;s not easy to restart your phone every time and resist unlocking it the first time.
So there is another way. Lock it through device administrator, i.e use any app which uses device administration right to lock your phone.</p>
<p>One such simple app is <a href="https://play.google.com/store/apps/details?id=com.iglint.android.screenlock">Screenlock</a>. You just need to tap it and sleep.</p>
<p>Hope the article helps. Keep your private chats private.</p>]]></content:encoded>
    </item>
    <item>
      <title>How to use &#39;xclip in Gnome Wayland&#39;</title>
      <link>https://www.geekyhub.in/post/use-xclip-in-gnome-wayland/</link>
      <pubDate>Sat, 03 Feb 2018 02:34:16 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/use-xclip-in-gnome-wayland/</guid>
      <description>TLDR, just use xclip -selection c</description>
      <content:encoded><![CDATA[<p>Since mainstream launch of Wayland with Gnome, people are facing problem in using xclip. Mainly because xclip is supposed to work with X11 Clipboard.</p>
<p>But fortunately there is an option in xclip to overcome this propblem.
Just use <em>xclip -selection c</em> instead of <em>xclip</em>. This option will just emulate the <em>ctrl + shift + c</em> action.</p>
<p>For easier use you can setup the alias by adding following line in <em>.bashrc</em> or <em>.zshrx</em> file.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>alias xclip<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;xclip -selection c&#39;</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Build a Simple WhatsApp bot in Python using Selenium</title>
      <link>https://www.geekyhub.in/post/making-a-whatsapp-bot-using-python-selenium/</link>
      <pubDate>Fri, 20 Oct 2017 17:51:16 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/making-a-whatsapp-bot-using-python-selenium/</guid>
      <description>DIY Article for building a simple WhatsApp bot using Python and Selenium</description>
      <content:encoded><![CDATA[<figure>
    <img loading="lazy" src="/images/robots-764951_640.png"/> 
</figure>

<p>Selenium is a web automation package available for all popular languages. To know more about selenium you can refer to <a href="http://docs.seleniumhq.org/">official Selenium docs</a>.
Here, we will be making a simple WhatsApp bot using Python and Selenium which will reply the current time for every message.</p>
<h2 id="installing-selenium">Installing Selenium</h2>
<p>So, first of all, we need to install Selenium for Python by running following command in terminal.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>pip install selenium 
</span></span></code></pre></div><p>Selenium also requires a driver to interface with the chosen browser. For Firefox, we need to install geckodriver. Without proper driver, you will get <em>WebDriverException</em>.</p>
<p>Download latest geckodriver from <a href="https://github.com/mozilla/geckodriver/releases">Mozilla&rsquo;s GitHub Repo</a> and add to the path.</p>
<h2 id="start-coding">Start Coding</h2>
<p>Now we are ready to proceed.
Make a new Python file i.e. <em>bot.py</em> and make some necessary imports.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">from</span> datetime <span style="color:#f92672">import</span> datetime
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> selenium <span style="color:#f92672">import</span> webdriver
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> selenium.webdriver.common.keys <span style="color:#f92672">import</span> Keys
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> selenium.common.exceptions <span style="color:#f92672">import</span> NoSuchElementException
</span></span></code></pre></div><p>Now we will create and initialize Firefox WebDriver and make a get request to open Whatsapp Web URL.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>driver <span style="color:#f92672">=</span> webdriver<span style="color:#f92672">.</span>Firefox()
</span></span><span style="display:flex;"><span>driver<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#39;http://web.whatsapp.com&#39;</span>)
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">&#39;Please Scan the QR Code and press enter&#39;</span>)
</span></span><span style="display:flex;"><span>input()
</span></span></code></pre></div><p>The <em>print</em> and <em>input</em> functions are there just to give us time to scan the QR code to connect our phone&rsquo;s WhatsApp. Once we are connected we can hit enter to continue further execution of code.</p>
<p>Once the WhatsApp Web interface is open, we need to look for unread messages. Thankfully, all unread messages in left pane are individual HTML element with CSS class &lsquo;chat unread&rsquo;.</p>
<p>WebDriver have a function to find elements by CSS selector which will return the first element with the given argument. We will make use of this function.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>content <span style="color:#f92672">=</span> driver<span style="color:#f92672">.</span>find_element_by_css_selector(<span style="color:#e6db74">&#39;.chat.unread&#39;</span>)
</span></span><span style="display:flex;"><span>content<span style="color:#f92672">.</span>click()
</span></span><span style="display:flex;"><span>input_form <span style="color:#f92672">=</span> driver<span style="color:#f92672">.</span>find_element_by_css_selector(<span style="color:#e6db74">&#39;.pluggable-input-placeholder&#39;</span>)
</span></span><span style="display:flex;"><span>input_form<span style="color:#f92672">.</span>send_keys(str(datetime<span style="color:#f92672">.</span>now()),Keys<span style="color:#f92672">.</span>RETURN)
</span></span></code></pre></div><p>Above code snippet is very simple. We are selecting first element with class <em>chat</em> and <em>unread</em> and clicking it. Then we need to find message box which is an HTML element with class <em>pluggable-input-placeholder</em>. <em>send_keys</em> function will send the keyboard event to the element. So we send the current time and RETURN key(Enter Key) to send the message.</p>
<p>As I have already mentioned that function <em>find_element_by_css_selector</em> will return only first element for given argument, So we need to put the whole snippet in a loop. Also, when there is no such element for the argument it will throw <em>NoSuchElementException</em>, so enclosing with <em>try</em> <em>except</em> is also necessary.</p>
<p>The final code will be</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">from</span> datetime <span style="color:#f92672">import</span> datetime
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> selenium <span style="color:#f92672">import</span> webdriver
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> selenium.webdriver.common.keys <span style="color:#f92672">import</span> Keys
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> selenium.common.exceptions <span style="color:#f92672">import</span> NoSuchElementException
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>driver <span style="color:#f92672">=</span> webdriver<span style="color:#f92672">.</span>Firefox()
</span></span><span style="display:flex;"><span>driver<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#39;http://web.whatsapp.com&#39;</span>)
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">&#39;Please Scan the QR Code and press enter&#39;</span>)
</span></span><span style="display:flex;"><span>input()
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">while</span> <span style="color:#66d9ef">True</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">try</span>:
</span></span><span style="display:flex;"><span>        content <span style="color:#f92672">=</span> driver<span style="color:#f92672">.</span>find_element_by_css_selector(<span style="color:#e6db74">&#39;.chat.unread&#39;</span>)
</span></span><span style="display:flex;"><span>        content<span style="color:#f92672">.</span>click()
</span></span><span style="display:flex;"><span>        input_form <span style="color:#f92672">=</span> driver<span style="color:#f92672">.</span>find_element_by_css_selector(<span style="color:#e6db74">&#39;.pluggable-input-placeholder&#39;</span>)
</span></span><span style="display:flex;"><span>        input_form<span style="color:#f92672">.</span>send_keys(str(datetime<span style="color:#f92672">.</span>now()),Keys<span style="color:#f92672">.</span>RETURN)
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">except</span> NoSuchElementException:
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">pass</span>
</span></span></code></pre></div><p>This code is just a proof of concept, you can obviously improve it for better performance.</p>]]></content:encoded>
    </item>
    <item>
      <title>Some &#39;cool&#39; things Visual Studio Code can do you may haven&#39;t known</title>
      <link>https://www.geekyhub.in/post/hidden-features-of-visual-studio-code/</link>
      <pubDate>Thu, 28 Sep 2017 16:35:16 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/hidden-features-of-visual-studio-code/</guid>
      <description>VSCode has established as a good text editor. Now let&amp;#39;s check out some of it&amp;#39;s cool features</description>
      <content:encoded><![CDATA[<p>Mircosoft&rsquo;s <a href="https://code.visualstudio.com/">Visual Studio Code</a> has proven to be the dark horse of code editors. Don&rsquo;t confuse yourself by seeing Microsoft as it is completely free, open source and MIT licensed.</p>
<p>Even being late to the party, it has attracted enough users. The reason behind this is a perfect balance between speed, features, and hackability.</p>
<p>If you are new to this editor, these are some features you should be known to improve your productivity.</p>
<h1 id="1-code-differs">1. Code Differs</h1>
<p>The files in your project look same but there are some differences. You spotted few of them just by gazing but there is still a chance of missing something. So why risk, just type the following command in your terminal and bam! VS Code will spot all the differences for you</p>
<pre><code>$code &lt;first-file&gt; &lt;second-file&gt;
</code></pre>
<figure>
    <img loading="lazy" src="/images/vscodediffer.png"/> <figcaption>
            VSCode Differ
        </figcaption>
</figure>

<h1 id="2-font-legatures">2. Font Legatures</h1>
<p>In typography, a ligature occurs where two or more letters are joined as a single glyph such as æ formed after joining a and e. In programming there are many token which are combination of two or more characters.
An example would be &lt; and = . <a href="https://github.com/tonsky/FiraCode">FiraCode</a> is programming ligature which will show &lt;= and many other token as single character. And FiraCode is easily installable in VSCode which isn&rsquo;t even supported by famous Sublime Text.</p>
<figure>
    <img loading="lazy" src="/images/firacode.jpg"/> <figcaption>
            Left: Without Firacode, Right: With Firacode
        </figcaption>
</figure>

<h1 id="3-type-checking-in-javascript">3. Type Checking in Javascript</h1>
<p>Typescript is typed superset of javascript. But in VSCode you can do all that in plain javascript by adding</p>
<pre><code>    //@ts-check
</code></pre>
<p>at top of the javascript file</p>
<figure>
    <img loading="lazy" src="/images/ts-check-in-javascript.gif"/> <figcaption>
            Demo for property and type checking
        </figcaption>
</figure>

<h1 id="4-the-printable-shortcut-cheatsheet">4. The Printable shortcut Cheatsheet</h1>
<p>A code editor is never good without good shortcut keys. VSCode offers a printable cheatsheet which you can paste on wall for quick learning. It contains shortcuts for important features like multiple cursors, integrated terminals, file management etc. Go explore it.</p>
<p>Download shortcut cheatsheet for
<a href="https://code.visualstudio.com/shortcuts/keyboard-shortcuts-windows.pdf">Windows</a>,
<a href="https://code.visualstudio.com/shortcuts/keyboard-shortcuts-linux.pdf">Linux</a> and
<a href="https://code.visualstudio.com/shortcuts/keyboard-shortcuts-macos.pdf">Mac</a>.</p>
<h1 id="5-change-case-of-variables">5. Change Case of variables</h1>
<p>Just select a variable (you can select multiple variables too), open Command Palette by pressing F1, Type change case and choose the case you want.
<figure>
    <img loading="lazy" src="/images/vscodechangecase.gif"/> <figcaption>
            Changing variable case in VSCode
        </figcaption>
</figure>
</p>]]></content:encoded>
    </item>
    <item>
      <title>Dear CS Freshman, Kali Linux is not what you are thinking</title>
      <link>https://www.geekyhub.in/post/you-shouldnt-begin-linux-with-kali/</link>
      <pubDate>Fri, 01 Sep 2017 04:23:00 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/you-shouldnt-begin-linux-with-kali/</guid>
      <description>Kali Linux is Not a Magical wand to make you a hacker, neither a stable linux to begin with</description>
      <content:encoded><![CDATA[<p>This post is intended for college Freshmans those who have little or no experience with Linux. If you are an experienced Linux user you may skip the post safely.</p>
<h2 id="what-is-linux">What is Linux?</h2>
<p>Linux is basically a term to refer all the distributions (or say OS) based on Linux Kernel collectively. some of its notable distributions are Ubuntu, Fedora, Arch, your favorite Kali Linux.</p>
<h2 id="where-may-you-have-heard-about-kali-linux">Where may you have heard about Kali Linux?</h2>
<p>I bet it is your friend or someone elder who said to you that Kali Linux can hack computers. I have seen students being obsessed with this distro without knowing anything about Linux.</p>
<figure>
    <img loading="lazy" src="/images/kalimeme.jpg"/> <figcaption>
            Easiest way to become a Hacker
        </figcaption>
</figure>

<p>Now hack is a stupid term. Most of the people think that it something by which you can access information without proper permission.  No, my friend, the term is much broader.</p>
<p>The <strong>hack</strong> is defined as &ldquo;a tip, trick, or efficient method for doing or managing something&rdquo; or in the Indian language, we say <em>Jugaad</em>.</p>
<h2 id="now-what-is-kali-linux">Now, What is Kali Linux?</h2>
<p>It is clearly written on their website that Kali Linux is Linux distribution aimed at advanced Penetration Testing and Security Auditing. Basically. it is a Linux Distro + set of tools.</p>
<h2 id="do-you-need-it">Do you need it?</h2>
<p><strong>No</strong>. Because you don&rsquo;t know yet that what is advanced Penetration Testing and Security Auditing. Just installing the OS will not make you a hacker. It is not a magic wand.</p>
<p>Even if you want to learn Linux it is not a good os to start with, because it is not intended for beginners. Also, it is not intended to be a workstation OS.
If you really want to learn Linux, go start with Ubuntu, Elementary OS, or Linux Mint. These are easy to setup and the online communities are beginner friendly.</p>
<p>Later on, you can get all those tool sets in Kali Linux in your current Linux OS. And after hopping distro, you will realize that every Linux based OS is same at heart.</p>]]></content:encoded>
    </item>
    <item>
      <title>Epic Pen is great Windows Ink workspace alternative for Windows 7</title>
      <link>https://www.geekyhub.in/post/screen_sketch_older_windows_7/</link>
      <pubDate>Wed, 02 Aug 2017 23:13:25 +0530</pubDate>
      <guid>https://www.geekyhub.in/post/screen_sketch_older_windows_7/</guid>
      <description>How to do screen sketch on Windows 7 and 8 such as Windows Ink workspace in Windows 10</description>
      <content:encoded><![CDATA[<p>Windows Ink workspace is great addition to Windows 10. Due to this tool, annotating has never been easier.</p>
<p>However, Windows 7 is still rock solid in the marked. Apart from corporate users many personal users are on Windows 7 which include my relatives.</p>
<p>When I use thier PC, only option to achieve the screen sketch is to take screenshot in paint and draw on it using pain. This method is not bad but also doesn&rsquo;t goes smoothly with my work flow. Mainly because it involes too much clicks</p>
<h2 id="3rd-party-app-to-rescue">3rd party app to rescue</h2>
<p><a href="http://epic-pen.com/">Epic Pen</a> is an application which puts a toolbar on screen with tools like pen, highlighter and eraser.</p>
<figure>
    <img loading="lazy" src="/images/windows_ink_windows_7_xp.png"/> <figcaption>
            Epic Pen in action
        </figcaption>
</figure>

<p>only basic difference in workflow is that in Epic Pen, you first draw on screen then take screenshot while in Widows Ink workspace, you first take screenshot then draw on it.</p>
<p>Epic Pen is free for personal use and can be downloaded from offical website.</p>]]></content:encoded>
    </item>
  </channel>
</rss>
