<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Uncategorized &#8211; Other Things</title>
	<atom:link href="https://blog.adamzolo.com/category/uncategorized/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.adamzolo.com</link>
	<description>Blog about Things by Adam Zolotarev</description>
	<lastBuildDate>Mon, 26 Jan 2026 16:10:56 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>
	<item>
		<title>How We Fixed the &#8220;First Web Container is Unhealthy&#8221; Error: A DNS Deep Dive</title>
		<link>https://blog.adamzolo.com/how-we-fixed-the-first-web-container-is-unhealthy-error-a-dns-deep-dive/</link>
					<comments>https://blog.adamzolo.com/how-we-fixed-the-first-web-container-is-unhealthy-error-a-dns-deep-dive/#respond</comments>
		
		<dc:creator><![CDATA[Adam Zolo]]></dc:creator>
		<pubDate>Mon, 26 Jan 2026 16:10:56 +0000</pubDate>
				<category><![CDATA[docker]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://blog.adamzolo.com/?p=1082</guid>

					<description><![CDATA[The Error That Nearly Broke Our Deployment Three hours into our Kamal deployment, we were stuck in a loop: ERROR Failed to boot web on {ip_address} INFO First web container is unhealthy on {ip_address}, not booting any other roles The container would start, but Kamal&#8217;s health check kept failing. After 30 seconds, Kamal would kill&#8230;<p><a class="more-link" href="https://blog.adamzolo.com/how-we-fixed-the-first-web-container-is-unhealthy-error-a-dns-deep-dive/" title="Continue reading &#8216;How We Fixed the &#8220;First Web Container is Unhealthy&#8221; Error: A DNS Deep Dive&#8217;">Continue reading <span class="meta-nav">&#8594;</span></a></p>]]></description>
										<content:encoded><![CDATA[<br />
<h2>The Error That Nearly Broke Our Deployment</h2>
<p>Three hours into our Kamal deployment, we were stuck in a loop:</p>
<pre><code>ERROR Failed to boot web on {ip_address}
  INFO First web container is unhealthy on {ip_address}, not booting any other roles</code></pre>
<p>The container would start, but Kamal&#8217;s health check kept failing. After 30 seconds, Kamal would kill the container<br />
   and retry, creating an endless loop.</p>
<p>We spent hours debugging deployment scripts, PostgreSQL configurations, and Rails settings. The fix turned out to<br />
  be much simpler: DNS configuration.</p>
<h2>The Root Cause: Broken DNS Resolution</h2>
<h3>What Was Happening</h3>
<p>When Kamal tried to verify container health, it performed this sequence:</p>
<ol>
<li>Container starts → my_app-web-abc123 boots</li>
<li>Traefik (Kamal proxy) tries to check /up endpoint</li>
<li>DNS lookup → Resolve my_app-web-abc123 to an IP address</li>
<li>Health check fails → DNS resolution times out or fails</li>
<li>Container killed → Kamal marks it as unhealthy</li>
</ol>
<h3>The DNS Failure</h3>
<p>The Traefik container&#8217;s /etc/resolv.conf showed:</p>
<pre><code>nameserver 127.0.0.53
  search members.linode.com
  options edns0 trust-ad ndots:0</code></pre>
<p><strong>Problem:</strong> 127.0.0.53 is the host&#8217;s systemd-resolved DNS server. It&#8217;s not accessible from inside<br />
  Docker containers!</p>
<p>When Traefik tried to resolve my_app-web-abc123:</p>
<ul>
<li>It queried 127.0.0.53 (systemd-resolved)</li>
<li>The query failed with &#8220;connection refused&#8221;</li>
<li>Health check failed</li>
<li>Container was killed</li>
</ul>
<h2>The Solution: Proper Docker DNS Configuration</h2>
<h3>What We Fixed</h3>
<p>We configured Docker&#8217;s DNS settings in <code>/etc/docker/daemon.json</code>:</p>
<pre><code>{
    "dns": ["127.0.0.11", "8.8.8.8", "1.1.1.1"]
  }</code></pre>
<h3>Why This Works</h3>
<p><strong>1. 127.0.0.11 (Docker&#8217;s Internal DNS) &#8211; First Priority</strong></p>
<ul>
<li>Resolves container hostnames automatically</li>
<li>Handles inter-container communication</li>
<li>Always available inside Docker networks</li>
</ul>
<p><strong>2. 8.8.8.8 (Google DNS) &#8211; Second Priority</strong></p>
<ul>
<li>Resolves external domains (APIs, gems, etc.)</li>
<li>Fast and reliable</li>
<li>Global infrastructure</li>
</ul>
<p><strong>3. 1.1.1.1 (Cloudflare DNS) &#8211; Third Priority</strong></p>
<ul>
<li>Privacy-focused external DNS</li>
<li>Backup if 8.8.8.8 fails</li>
<li>No query logging</li>
</ul>
<h3>How Docker Uses This</h3>
<p>Docker&#8217;s DNS resolution order:</p>
<ol>
<li>Try 127.0.0.11 (internal) → container names</li>
<li>If that fails → 8.8.8.8 (external) → domains</li>
<li>If that fails → 1.1.1.1 (external) → domains</li>
</ol>
<h2>The IPv4/IPv6 Issue</h2>
<p>While debugging, we discovered another subtle problem:</p>
<h3>The IPv6 Trap</h3>
<p>The server setup script used:</p>
<pre><code>SERVER_IP=$(curl -s ifconfig.me || echo "ip_address_goes_here")</code></pre>
<p><strong>Problem:</strong> ifconfig.me returned an IPv6 address:</p>
<pre><code>2600:3c03::...</code></pre>
<p>This IPv6 address was used in PostgreSQL&#8217;s pg_hba.conf:</p>
<pre><code>host my_app_production my_app_user 2600:3c03.../32 md5</code></pre>
<p>PostgreSQL had issues with this IPv6 address, causing authentication failures.</p>
<h3>The Fix</h3>
<p>Force IPv4 detection:</p>
<pre><code>SERVER_IP=$(curl -s -4 ifconfig.me || echo "ip_address_goes_here")</code></pre>
<p>The <code>-4</code> flag ensures we always get an IPv4 address, which PostgreSQL handles reliably.</p>
<h2>The PostgreSQL Network Isolation Issue</h2>
<h3>The Problem</h3>
<p>Kamal uses a separate Docker network (172.18.0.0/16) for containers, while PostgreSQL is on the host&#8217;s Docker<br />
  bridge network (172.17.0.0/16).</p>
<p>The firewall only allowed 172.17.0.0/16:</p>
<pre><code>5432/tcp  ALLOW  172.17.0.0/16</code></pre>
<h3>The Fix</h3>
<p>Add the Kamal network to both firewall and PostgreSQL config:</p>
<p><strong>Firewall (ufw):</strong></p>
<pre><code>sudo ufw allow from 172.18.0.0/16 to any port 5432</code></pre>
<p><strong>PostgreSQL (pg_hba.conf):</strong></p>
<pre><code>host my_app_production my_app_user 172.18.0.0/16 md5</code></pre>
<h2>Complete Fix in our setup script</h2>
<h3>IPv4 Fix </h3>
<pre><code>SERVER_IP=$(curl -s -4 ifconfig.me || echo "ip_address_goes_here")</code></pre>
<h3>Kamal Network Firewall Rule</h3>
<pre><code>sudo ufw allow from 172.18.0.0/16 to any port 5432</code></pre>
<h3>PostgreSQL Kamal Network Rule </h3>
<pre><code>host $DB_NAME $DB_USER 172.18.0.0/16 md5</code></pre>
<h3>Docker DNS Configuration </h3>
<pre><code>{
    "dns": ["127.0.0.11", "8.8.8.8", "1.1.1.1"]
  }</code></pre>
<h2>Key Takeaways</h2>
<ol>
<li><strong>DNS is Critical for Container Orchestration</strong>
<ul>
<li>Always configure Docker&#8217;s DNS properly</li>
<li>Include both internal and external DNS servers</li>
<li>Test DNS resolution from containers</li>
</ul>
</li>
<li><strong>Network Isolation Matters</strong>
<ul>
<li>Docker networks are isolated by default</li>
<li>PostgreSQL must allow connections from all Docker networks</li>
<li>Firewall rules must match</li>
</ul>
</li>
<li><strong>IPv4 vs IPv6 Can Break Things</strong>
<ul>
<li>PostgreSQL works better with IPv4</li>
<li>Force IPv4 when detecting server IPs</li>
<li>Test both IPv4 and IPv6 connectivity</li>
</ul>
</li>
<li><strong>Health Checks are Essential</strong>
<ul>
<li>The /up endpoint is critical for Kamal</li>
<li>DNS must work for health checks to succeed</li>
<li>Timeout settings matter (30s default)</li>
</ul>
</li>
</ol>
<h2>Troubleshooting DNS Issues</h2>
<p>If you encounter &#8220;First web container is unhealthy&#8221;:</p>
<ol>
<li><strong>Check Container Logs</strong><br />
  <code>docker logs my_app-web-abc123</code></li>
<li><strong>Check Traefik/Kamal Proxy Logs</strong><br />
  <code>docker logs kamal-proxy | grep -i healthcheck</code></li>
<li><strong>Test DNS Resolution</strong>
<pre><code># From inside Traefik container
  docker exec kamal-proxy getent hosts my_app-web-abc123
  docker exec kamal-proxy getent hosts google.com</code></pre>
</li>
<li><strong>Verify DNS Configuration</strong>
<pre><code># Check daemon.json
  cat /etc/docker/daemon.json

  # Check container's resolv.conf
  docker exec kamal-proxy cat /etc/resolv.conf</code></pre>
</li>
<li><strong>Check PostgreSQL Connectivity</strong>
<pre><code># From kamal network
  docker run --rm --network kamal postgres:16 psql \
    -h 172.17.0.1 -U my_app_user -d my_app_production -c "SELECT 1"</code></pre>
</li>
</ol>
<h2>Results</h2>
<p>After implementing all fixes:</p>
<ul>
<li><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> DNS resolution works (internal and external)</li>
<li><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Health checks pass (Traefik can reach containers)</li>
<li><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> PostgreSQL connections work (from both Docker networks)</li>
<li><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Deployments succeed (consistent, reliable)</li>
<li><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> IPv4 detection works (no IPv6 issues)</li>
</ul>
<h2>Final Thoughts</h2>
<p>The &#8220;First web container is unhealthy&#8221; error can be a DNS configuration issue, not a deployment or application<br />
  problem.</p>
<p>By understanding how Docker networks work, how DNS resolution functions, and how PostgreSQL authentication works, we can prevent this issue from ever occurring again.</p>
<p><strong>Key files to review:</strong></p>
<ul>
<li><code>/etc/docker/daemon.json</code> &#8211; Docker DNS configuration</li>
<li><code>/etc/postgresql/16/main/pg_hba.conf</code> &#8211; PostgreSQL authentication</li>
<li><code>/etc/ufw/rules.conf</code> &#8211; Firewall rules</li>
</ul>
<p>The fix is now automated in our setup script, ensuring new servers have proper DNS and network configuration from<br />
  day one.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.adamzolo.com/how-we-fixed-the-first-web-container-is-unhealthy-error-a-dns-deep-dive/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Setting up a cron job on Mac</title>
		<link>https://blog.adamzolo.com/setting-up-cron-job-on-mac/</link>
					<comments>https://blog.adamzolo.com/setting-up-cron-job-on-mac/#respond</comments>
		
		<dc:creator><![CDATA[Adam Zolo]]></dc:creator>
		<pubDate>Fri, 23 Jun 2017 23:51:33 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://blog.adamzolo.com/?p=622</guid>

					<description><![CDATA[In this example, we&#8217;re setting up a job, which will run at 08:00 am daily and clean rails logs Step 1 &#8211; create a file with what we want to run (delete_logs.sh): Setp 2 &#8211; set up the cron scheduler:]]></description>
										<content:encoded><![CDATA[<p>In this example, we&#8217;re setting up a job, which will run at 08:00 am daily and clean rails logs</p>
<p>Step 1 &#8211; create a file with what we want to run (delete_logs.sh):</p>
<pre class="brush: plain; title: ; notranslate">
#!/bin/(shell) 

cd ~/code/rails_project
/Users/username/.rbenv/shims/bundle exec rake log:clear
</pre>
<p>Setp 2 &#8211; set up the cron scheduler:</p>
<pre class="brush: plain; title: ; notranslate">
$ env EDITOR=vim crontab -e

# Add the line to run the script at 8am daily:

0 8 * * * sh ~/scripts/delete_logs.sh &gt;/tmp/stdout.log 2&gt;/tmp/stderr.log
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.adamzolo.com/setting-up-cron-job-on-mac/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Phoenix and Ecto. First Steps</title>
		<link>https://blog.adamzolo.com/phoenix-and-ecto-first-steps/</link>
					<comments>https://blog.adamzolo.com/phoenix-and-ecto-first-steps/#respond</comments>
		
		<dc:creator><![CDATA[Adam Zolo]]></dc:creator>
		<pubDate>Thu, 06 Apr 2017 22:02:33 +0000</pubDate>
				<category><![CDATA[Elixir]]></category>
		<category><![CDATA[Phoenix]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://blog.adamzolo.com/?p=483</guid>

					<description><![CDATA[Valid as of Phoenix 1.2 Show routes: mix phoenix.routes Generating resources: mix phoenix.gen.html Post posts &#8211;no-model mix phoenix.gen.json Post posts Ecto Types :string :integer :map :binary_id :float :boolean Writing Queries Two ways Query import Ecto.Query from p in context.Posts where p.Title.Contains(&#34;Stuff&#34;) select p; Expression MyApp.Post &#124;&#62; where(titlle: &#34;Stuff&#34;) &#124;&#62; limit(1) Making changes &#8211; https://hexdocs.pm/ecto/Ecto.Changeset.html changeset&#8230;<p><a class="more-link" href="https://blog.adamzolo.com/phoenix-and-ecto-first-steps/" title="Continue reading &#8216;Phoenix and Ecto. First Steps&#8217;">Continue reading <span class="meta-nav">&#8594;</span></a></p>]]></description>
										<content:encoded><![CDATA[<p>Valid as of Phoenix 1.2</p>
<p>Show routes:<br />
mix phoenix.routes</p>
<p>Generating resources:<br />
mix phoenix.gen.html Post posts &#8211;no-model<br />
mix phoenix.gen.json Post posts</p>
<p><strong>Ecto</strong><br />
Types</p>
<ul>
<li>:string</li>
<li>:integer</li>
<li>:map</li>
<li>:binary_id</li>
<li>:float</li>
<li>:boolean</li>
</ul>
<p><strong>Writing Queries</strong><br />
Two ways</p>
<ol>
<li><a href="https://hexdocs.pm/ecto/Ecto.Query.html" target="_blank">Query</a>
<pre class="brush: plain; title: ; notranslate">
import Ecto.Query

from p in context.Posts
where p.Title.Contains(&quot;Stuff&quot;)
select p;
</pre>
</li>
<li>Expression
<pre class="brush: plain; title: ; notranslate">
MyApp.Post
|&gt; where(titlle: &quot;Stuff&quot;)
|&gt; limit(1)
</pre>
</li>
</ol>
<p>Making changes &#8211; https://hexdocs.pm/ecto/Ecto.Changeset.html<br />
changeset = Post.changeset(post, %{title: &#8220;updated&#8221;})<br />
Repo.update(changeset)<br />
Repo.delete(post)</p>
<p>Migrations<br />
Generate migration:<br />
mix ecto.gen.migration [migration_name] -r [repo]</p>
<p>Generate schema:<br />
mix phoenix.gen.model [Schema] [table] [fields] -r [repo]</p>
<p>Run/Rollback migration<br />
mix ecto.migrate -r [repo]<br />
mix ecto.rollback -r [repo]</p>
<p>Generate migration:<br />
Does not generate schema module:<br />
mix ecto.gen.migration [migration_name] -r [repo]</p>
<p>Generates both schema model and a migration:<br />
mix phoenix.gen.model [Schema] [table] [fields] -r [repo]</p>
<p>To avoid specifying repo all the time:<br />
config :my_app, ecto_repos: [MyApp.Repo]</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.adamzolo.com/phoenix-and-ecto-first-steps/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Ruby/Rails Training Resources</title>
		<link>https://blog.adamzolo.com/rubyrails-training-resources/</link>
					<comments>https://blog.adamzolo.com/rubyrails-training-resources/#respond</comments>
		
		<dc:creator><![CDATA[Adam Zolo]]></dc:creator>
		<pubDate>Tue, 11 Oct 2016 18:47:03 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://blog.adamzolo.com/?p=376</guid>

					<description><![CDATA[http://exercism.io/ &#8211; exercises in many languages, including Ruby http://paircolumbus.org https://www.railstutorial.org/ https://www.codecademy.com/ http://docs.railsbridge.org/ https://online.pragmaticstudio.com/ &#8211; online course (not free, but pretty good)]]></description>
										<content:encoded><![CDATA[<ul>
<li><a href="http://exercism.io/" target="_blank">http://exercism.io/</a> &#8211; exercises in many languages, including Ruby</li>
<li><a href="http://paircolumbus.org" target="_blank">http://paircolumbus.org</a></li>
<li><a href="https://www.railstutorial.org/" target="_blank">https://www.railstutorial.org/</a></li>
<li><a href="https://www.codecademy.com/" target="_blank">https://www.codecademy.com/</a></li>
<li><a href="http://docs.railsbridge.org/" target="_blank">http://docs.railsbridge.org/</a></li>
<li><a href="https://online.pragmaticstudio.com/" target="_blank">https://online.pragmaticstudio.com/</a> &#8211; online course (not free, but pretty good)</li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.adamzolo.com/rubyrails-training-resources/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Fira Code with Visual Studio</title>
		<link>https://blog.adamzolo.com/fira-code-with-visual-studio/</link>
					<comments>https://blog.adamzolo.com/fira-code-with-visual-studio/#respond</comments>
		
		<dc:creator><![CDATA[Adam Zolo]]></dc:creator>
		<pubDate>Mon, 05 Sep 2016 21:43:02 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://blog.adamzolo.com/?p=340</guid>

					<description><![CDATA[Fira Code &#8211; a pretty cool font with a set of ligatures for common programming multi-character combinations. To install &#8211; download from https://github.com/tonsky/FiraCode. Install the fonts from ttf folder Pick your fonts in VS (Tools &#8211; Options &#8211; Fonts and Colors)]]></description>
										<content:encoded><![CDATA[<p>Fira Code &#8211; a pretty cool font with a set of ligatures for common programming multi-character combinations.</p>
<p>To install &#8211; download from <a href="https://github.com/tonsky/FiraCode">https://github.com/tonsky/FiraCode</a>.</p>
<p>Install the fonts from ttf folder</p>
<p>Pick your fonts in VS (Tools &#8211; Options &#8211; Fonts and Colors)</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.adamzolo.com/fira-code-with-visual-studio/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Setting up Elixir with Atom on Linux</title>
		<link>https://blog.adamzolo.com/setting-elixir-atom-linux/</link>
					<comments>https://blog.adamzolo.com/setting-elixir-atom-linux/#respond</comments>
		
		<dc:creator><![CDATA[Adam Zolo]]></dc:creator>
		<pubDate>Sun, 17 Jul 2016 18:51:44 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://www.eazolo.com/blog/?p=322</guid>

					<description><![CDATA[Sublime is a pretty nice editor for working with Elixir, but I just can&#8217;t get the autocomplete plugin to work. So, giving Atom a try. Install the following packages: atom-elixir &#8211; https://atom.io/packages/atom-elixir language-elixir &#8211; https://atom.io/packages/language-elixir linter (apm install linter) &#8211; https://atom.io/packages/linter linter-elixirc &#8211; https://atom.io/packages/linter-elixirc script &#8211; https://atom.io/packages/script I use script to build within Atom (shift-ctrl-b).&#8230;<p><a class="more-link" href="https://blog.adamzolo.com/setting-elixir-atom-linux/" title="Continue reading &#8216;Setting up Elixir with Atom on Linux&#8217;">Continue reading <span class="meta-nav">&#8594;</span></a></p>]]></description>
										<content:encoded><![CDATA[<p>Sublime is a pretty nice editor for working with Elixir, but I just can&#8217;t get the autocomplete plugin to work. So, giving Atom a try.</p>
<p>Install the following packages:</p>
<p>atom-elixir &#8211; <a href="https://atom.io/packages/atom-elixir" target="_blank">https://atom.io/packages/atom-elixir</a><br />
language-elixir &#8211; <a href="https://atom.io/packages/language-elixir" target="_blank">https://atom.io/packages/language-elixir</a><br />
linter (apm install linter) &#8211; https://atom.io/packages/linter<br />
linter-elixirc &#8211; <a href="https://atom.io/packages/linter-elixirc" target="_blank">https://atom.io/packages/linter-elixirc</a><br />
script &#8211; <a href="https://atom.io/packages/script" target="_blank">https://atom.io/packages/script</a></p>
<p>I use script to build within Atom (shift-ctrl-b). The only issue is that it seems to use the top-level folder of your project as a base path. So, if you try to do something like Code.load_file(&#8220;file.exs&#8221;) in one of your nested directories, it&#8217;ll try to load it from the top level directory.</p>
<p><strong>Addendum for Mac</strong><br />
brew install elixir<br />
brew install erlang</p>
<p>Set elixir path for autocomplete-elixir (if using Atom):<br />
/usr/local/bin/elixir</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.adamzolo.com/setting-elixir-atom-linux/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Parsing jQuery Unobtrusive Validation Parameters</title>
		<link>https://blog.adamzolo.com/parsing-jquery-unobtrusive-validation-parameters/</link>
					<comments>https://blog.adamzolo.com/parsing-jquery-unobtrusive-validation-parameters/#respond</comments>
		
		<dc:creator><![CDATA[Adam Zolo]]></dc:creator>
		<pubDate>Thu, 14 Jul 2016 02:15:46 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://www.eazolo.com/blog/?p=318</guid>

					<description><![CDATA[Client-side parsing of unubtrusive jQuery validation parameters. Assuming we are setting up an unobtrusive validator named &#8220;validatorname&#8221; and want to pass &#8220;parameterfromserver&#8221; from the the server: $.validator.unobtrusive.adapters.add('validatorname', &#x5B;'parameterfromserver'], function(options) { options.rules&#x5B;'validatorname'] = { parameterfromserver: options.params&#x5B;'parameterfromserver'] }; options.messages&#x5B;'validatorname'] = options.message; }); $.validator.addMethod('validatorname', function(value, element, parameters) { var hereIsOurParameter = parameters.parameterfromserver; });]]></description>
										<content:encoded><![CDATA[<p>Client-side parsing of unubtrusive jQuery validation parameters. Assuming we are setting up an unobtrusive validator named &#8220;validatorname&#8221; and want to pass &#8220;parameterfromserver&#8221; from the the server:</p>
<pre class="brush: jscript; title: ; notranslate">
$.validator.unobtrusive.adapters.add('validatorname', &#x5B;'parameterfromserver'], function(options) {
	options.rules&#x5B;'validatorname'] = {
		parameterfromserver: options.params&#x5B;'parameterfromserver']
	};
	options.messages&#x5B;'validatorname'] = options.message;
});
$.validator.addMethod('validatorname', function(value, element, parameters) {
	var hereIsOurParameter = parameters.parameterfromserver;
});
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.adamzolo.com/parsing-jquery-unobtrusive-validation-parameters/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Visual Studio Locate File In Solution Explorer without Resharper</title>
		<link>https://blog.adamzolo.com/locate-file-in-solution-explorer/</link>
					<comments>https://blog.adamzolo.com/locate-file-in-solution-explorer/#respond</comments>
		
		<dc:creator><![CDATA[Adam Zolo]]></dc:creator>
		<pubDate>Sat, 30 Jan 2016 14:58:00 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://www.eazolo.com/blog/?p=195</guid>

					<description><![CDATA[Visual Studio 2015 has built-in functionality to locate a currently open file in the Solution Explorer using a shortcut. No need for any extensions. Go to Tools &#8211; Options &#8211; Environment &#8211; Keyboard. Find SolutionExplorer.SyncWithActiveDocument. Assign a shortcut. Done.]]></description>
										<content:encoded><![CDATA[<p>Visual Studio 2015 has built-in functionality to locate a currently open file in the Solution Explorer using a shortcut. No need for any extensions.</p>
<p>Go to Tools &#8211; Options &#8211; Environment &#8211; Keyboard.<br />
Find SolutionExplorer.SyncWithActiveDocument.<br />
Assign a shortcut.</p>
<p>Done.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.adamzolo.com/locate-file-in-solution-explorer/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>One Hand Typing</title>
		<link>https://blog.adamzolo.com/one-hand-typing/</link>
					<comments>https://blog.adamzolo.com/one-hand-typing/#respond</comments>
		
		<dc:creator><![CDATA[Adam Zolo]]></dc:creator>
		<pubDate>Mon, 07 Dec 2015 16:35:45 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://www.eazolo.com/blog/?p=190</guid>

					<description><![CDATA[If you have to type with one hand, AutoHotkey is a free option to turn your regular keyboard into a half mirror keyboard, where each key on one side is mirrored to the other (activate it by pressing Space key first). Here&#8217;s a script, copied from AutoHotkey forum with slight modifications: #SingleInstance, force ; Half-QWERTY:&#8230;<p><a class="more-link" href="https://blog.adamzolo.com/one-hand-typing/" title="Continue reading &#8216;One Hand Typing&#8217;">Continue reading <span class="meta-nav">&#8594;</span></a></p>]]></description>
										<content:encoded><![CDATA[<p>If you have to type with one hand, AutoHotkey is a free option to turn your regular keyboard into a half mirror keyboard, where each key on one side is mirrored to the other (activate it by pressing Space key first).</p>
<p>Here&#8217;s a script, copied from <a href="http://www.autohotkey.com/forum/viewtopic.php?p=228783#228783">AutoHotkey forum</a> with slight modifications:</p>
<p><code>#SingleInstance, force<br />
; Half-QWERTY: One-handed Typing - version 3a<br />
; http://www.autohotkey.com/forum/viewtopic.php?p=228783#228783<br />
;<br />
; HalfKeyboard invented by Matias Corporation between 1992 and 1996<br />
; Originally coded in AutoHotkey by jonny in 2004<br />
; Many thanks to Chris for helping him out with this script.<br />
; Capslock hacks and `~ remap to '" by Watcher<br />
; This implementation was done by mbirth in 2007<br />
;<br />
; version 3a script, mod by hugov:<br />
; 2008-10-31:<br />
; - mixed with "Capitalize letters after 1 second hold" at request of Calibran<br />
;   http://www.autohotkey.com/forum/post-228311.html#228311<br />
;   just tested very briefly so try at your own peril :-)<br />
;</p>
<p>KeyIsDown = 0<br />
UpperDelay = 300<br />
UpperDelay *= -1</p>
<p>RegRead KLang, HKEY_CURRENT_USER, Keyboard Layout\Preload, 1<br />
StringRight KLang, KLang, 4<br />
If (!KLang)<br />
  KLang := A_Language</p>
<p>If (KLang = "0407") {<br />
  ; 0407 DE_de QWERTZ mirror set<br />
  original := "^12345qwertasdfgyxcvb"<br />
  mirrored := "ß09876poiuzölkjh-.,mn"<br />
} Else If (KLang = "040c" || KLang = "040C") {<br />
  ; 040c FR_fr AZERTY mirror set<br />
  original := "²&é" . """" . "'(azertqsdfgwxcvb"   ; split up string for better<br />
  mirrored := ")àç" . "_"  . "è-poiuymlkjh!:;,n"   ; human readability<br />
} Else {<br />
  ; 0409 US_us QWERTY mirror set<br />
  original := "``" . "12345qwertasdfgzxcvb"   ; split up string for better<br />
  mirrored := "'"  . "09876poiuy;lkjh/.,mn"   ; human readability<br />
}</p>
<p>; Now define all hotkeys<br />
Loop % StrLen(original)<br />
{<br />
  c1 := SubStr(original, A_Index, 1)<br />
  c2 := SubStr(mirrored, A_Index, 1)<br />
  Hotkey Space & %c1%, DoHotkey<br />
  Hotkey Space & %c2%, DoHotkey<br />
  Hotkey %c1%, KeyDown<br />
  Hotkey %c1% UP, KeyUP<br />
  Hotkey %c2%, KeyDown ;<br />
  Hotkey %c2% UP, KeyUP ;<br />
}</p>
<p>return</p>
<p>; This key may help, as the space-on-up may get annoying, especially if you type fast.<br />
Control & Space::Suspend</p>
<p>; Not exactly mirror but as close as we can get, Capslock enter, Tab backspace.<br />
Space & CapsLock::Send {Enter}<br />
Space & Tab::Send {Backspace}</p>
<p>; If spacebar didn't modify anything, send a real space keystroke upon release.<br />
+Space::Send {Space}<br />
Space::Send {Space}</p>
<p>; General purpose<br />
DoHotkey:<br />
  StartTime := A_TickCount<br />
  StringRight ThisKey, A_ThisHotkey, 1<br />
  i1 := InStr(original, ThisKey)<br />
  i2 := InStr(mirrored, ThisKey)<br />
  If (i1+i2 = 0) {<br />
    MirrorKey := ThisKey<br />
  } Else If (i1 > 0) {<br />
    MirrorKey := SubStr(mirrored, i1, 1)<br />
  } Else {<br />
    MirrorKey := SubStr(original, i2, 1)<br />
  }</p>
<p>  Modifiers := ""<br />
  If (GetKeyState("LWin") || GetKeyState("RWin")) {<br />
    Modifiers .= "#"<br />
  }<br />
  If (GetKeyState("Control")) {<br />
    Modifiers .= "^"<br />
  }<br />
  If (GetKeyState("Alt")) {<br />
    Modifiers .= "!"<br />
  }<br />
  If (GetKeyState("Shift") + GetKeyState("CapsLock", "T") = 1) {<br />
    ; only add if Shift is held OR CapsLock is on (XOR) (both held down would result in value of 2)<br />
    Modifiers .= "+"<br />
  }</p>
<p>If (KeyIsDown < 1 or ThisKey <> LastKey)<br />
          {<br />
               KeyIsDown := True<br />
               LastKey := ThisKey<br />
               Send %Modifiers%{%MirrorKey%}<br />
               SetKeyDelay, 65535<br />
               SetTimer, ReplaceWithUpperMirror, %UpperDelay%<br />
          }</p>
<p>Return</p>
<p>MenuShowKeyboardLayout:<br />
IfWinNotExist, HalfKeyboard - permanent keyboard layout<br />
	{<br />
 	 Gui, +Owner +Toolwindow +AlwaysOnTop<br />
	 Gui, Add, picture, x0 y0 w310 h104, %A_ScriptDir%\halfkeyboard_help.png<br />
	 Gui, Show, w310 h104 NA, HalfKeyboard - permanent keyboard layout<br />
	 Menu, Tray, Check, &Show Keyboard layout<br />
	}<br />
Else<br />
	{<br />
	 Gosub, GuiClose<br />
	}<br />
Return</p>
<p>GuiClose:<br />
Menu, Tray, UnCheck, &Show Keyboard layout<br />
Gui, Destroy<br />
Return</p>
<p>MenuExit:<br />
  ExitApp<br />
Return</p>
<p>KeyDown:<br />
   Key:=A_ThisHotkey<br />
        If (KeyIsDown < 1 or Key <> LastKey)<br />
           {<br />
                KeyIsDown := True<br />
                LastKey := Key<br />
                Send %Key%<br />
                SetKeyDelay, 65535<br />
                SetTimer, ReplaceWithUpper, %UpperDelay%<br />
           }<br />
        Return</p>
<p>KeyUp:<br />
   Key:=A_ThisHotkey<br />
        SetTimer, ReplaceWithUpper, Off<br />
        SetTimer, ReplaceWithUpperMirror, Off<br />
        KeyIsDown := False<br />
        Return</p>
<p>ReplaceWithUpper:<br />
SetKeyDelay, -1<br />
Send {Backspace}+%LastKey%<br />
Return</p>
<p>ReplaceWithUpperMirror:<br />
SetKeyDelay, -1<br />
Send {Backspace}+%MirrorKey%<br />
Return</p>
<p></code></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.adamzolo.com/one-hand-typing/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Exceptionless Self-Hosting Tips</title>
		<link>https://blog.adamzolo.com/exceptionless/</link>
					<comments>https://blog.adamzolo.com/exceptionless/#respond</comments>
		
		<dc:creator><![CDATA[Adam Zolo]]></dc:creator>
		<pubDate>Sat, 21 Nov 2015 22:53:26 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://www.eazolo.com/blog/?p=151</guid>

					<description><![CDATA[Exceptionless is an awesome open source real-time error, feature, and log reporting solution that can be self-hosted for free (they provide a very reasonable pricing plans as well). Here&#8217;re some tips on self-hosting in the Windows environment. Use these detailed instructions to set it up. Instructions are quite good. However, there are some details not&#8230;<p><a class="more-link" href="https://blog.adamzolo.com/exceptionless/" title="Continue reading &#8216;Exceptionless Self-Hosting Tips&#8217;">Continue reading <span class="meta-nav">&#8594;</span></a></p>]]></description>
										<content:encoded><![CDATA[<p><a href="https://github.com/exceptionless/Exceptionless" target="_blank">Exceptionless</a> is an awesome open source real-time error, feature, and log reporting solution that can be self-hosted for free (they provide a very reasonable pricing plans as well). Here&#8217;re some tips on self-hosting in the Windows environment. </p>
<p>Use <a href="https://github.com/exceptionless/Exceptionless/wiki/Self-Hosting" target="_blank">these detailed instructions</a> to set it up. Instructions are quite good. However, there are some details not mentioned in the guide which you could find helpful for self-hosting.</p>
<p><strong>Elastic Search</strong></p>
<p>When setting up Elastic Search, it&#8217;s a good idea to change the default location of the data folder. It can help avoid an accidental loss of your data when updating to the next version of Elastic Search. The data path can be set in the elasticsearch.yml &#8211; &#8220;path.data&#8221; property.</p>
<p>Rename your cluster name &#8211; &#8220;cluster.name&#8221; property. This can help prevent someone from accidentally joining your cluster.</p>
<p>To directly query Elastic Search, you can install Sense chrome plugin and run queries inside Chrome.</p>
<p>Another useful ES GUI plugin: elasticsearch-gui<br />
To install, run cmd from ES installation bin folder: [~/elasticsearch] $ bin/plugin &#8211;install jettro/elasticsearch-gui<br />
To access it, go to http://yourServer:9200/_plugin/gui/index.html#/dashboard (assuming default ES port 9200)</p>
<p>If you want to set up backups for ES, first set the repo location in elasticsearch.yml<br />
path.repo: [&#8220;backupLocation&#8221;]</p>
<p>From Chrome, Sense plugin, run the following query to create a repo for your backups:</p>
<pre class="brush: plain; title: ; notranslate">
PUT /_snapshot/exceptionless_backup
{
  &quot;type&quot;: &quot;fs&quot;,
   &quot;settings&quot;: {
        &quot;compress&quot; : true,
        &quot;location&quot;: &quot;backupLocation&quot;
    }
}
</pre>
<p>When you want to create a snapshot, run:</p>
<pre class="brush: plain; title: ; notranslate">
PUT /_snapshot/exceptionless_backup/yourShapshotName?wait_for_completion=true
</pre>
<p>To delete an old snapshot:</p>
<pre class="brush: plain; title: ; notranslate">
DELETE _snapshot/exceptionless_backup/yourShapshotName
</pre>
<p><strong>Removing Old Data</strong><br />
Exceptionless provides a job which will automatically remove data over a given retention period. But if you self-host, the retention period is indefinite. If you prefer to have Exceptionless remove the old automatically, you can modify the retention period directly in the Elastic Search. Run the following ES query to set retention period to 45 days:</p>
<pre class="brush: plain; title: ; notranslate">
POST /organizations-v1/organization/YourOrganizationId/_update '{ &quot;doc&quot; : 
{
    &quot;doc&quot; : {        
 &quot;_source&quot;: {
     &quot;retention_days&quot;: 45
   }
    }
}
</pre>
<p>You can use Elasticsearch-gui plugin to figure out your organization Id.</p>
<p><strong>Weirdness with IE 11. </strong><br />
For some reason IE 11 did not want to auto refresh itself. So, you could add these headers at IIS level:<br />
Cache-Control:no-cache, no-store<br />
Pragma:no-cache<br />
This comes at the price of more hits to your server. But I couldn&#8217;t figure out the IE issue.</p>
<p><strong>Redis</strong><br />
If you use Redis (recommended), this is how you specify the connection string:</p>
<pre class="brush: plain; title: ; notranslate">
&lt;add name=&quot;RedisConnectionString&quot; connectionString=&quot;serverName:6379&quot; /&gt;
</pre>
<p>The important part is that there is no http in the server name</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.adamzolo.com/exceptionless/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
