<?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>nivas,b:=log()</title>
	<atom:link href="https://www.nivas.hr/blog/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.nivas.hr/blog</link>
	<description>This is a blog from the Nivas.hr crew to the galaxy of unknown. </description>
	<lastBuildDate>Tue, 19 Sep 2017 12:50:51 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.8.2</generator>
	<item>
		<title>Measuring Disk IO Performance on MacOS</title>
		<link>https://www.nivas.hr/blog/2017/09/19/measuring-disk-io-performance-macos/</link>
					<comments>https://www.nivas.hr/blog/2017/09/19/measuring-disk-io-performance-macos/#comments</comments>
		
		<dc:creator><![CDATA[seven]]></dc:creator>
		<pubDate>Tue, 19 Sep 2017 12:50:51 +0000</pubDate>
				<category><![CDATA[apple]]></category>
		<category><![CDATA[developers journal]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[macos]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2573</guid>

					<description><![CDATA[Over time and numerous hardware updates around the office, I collected a vast number of 2.5&#8243; HDD&#8217;s in my &#8220;hardware junk&#8221; box. The other day, I noticed two Kingston SSDNow V200 128GB SSD&#8217;s just sitting there doing nothing, so I decided to make them usable again. I have a really BAD track record of broken...]]></description>
										<content:encoded><![CDATA[<p>Over time and numerous hardware updates around the office, I collected a vast number of 2.5&#8243; HDD&#8217;s in my &#8220;hardware junk&#8221; box. The other day, I noticed two Kingston SSDNow V200 128GB SSD&#8217;s just sitting there doing nothing, so I decided to make them usable again. I have a really BAD track record of broken non-ssd 2.5&#8243; travelling external disks. 99% of them broke or started showing serious problems just after 1st year of usage (traveling with them with the notebook). I wanted to see how will SSD disk act in same conditions.</p>
<p>I visited my local hardware store to get USB3 2.5&#8243; HDD enclosure, being geek, I did my homework and decided to get noname enclosure for 15 EUR with semi rubber protection.<br />
Good lady at the counter suggested that instead of 15EUR one, I get 13EUR noname enclosure since &#8220;it was better&#8221;. </p>
<p>Sceptical that I am, I bought both and decided to do a test and prove her that she is wrong. The one with higher price had to be better. :)</p>
<p>After fitting disks in enclosures, first issue I stumbled upon was a lack of disk benchmarking tool on MacOS. On Windows I used <a href="http://www.hdtune.com/">hdtune</a> for ages and was happy with it. On MacOS however, <a href="https://itunes.apple.com/us/app/blackmagic-disk-speed-test/id425264550?mt=12">Blackmagic Disk Speed Test</a> in Mac App Store did not inspire confidence in me (blac kmagic, cmon?), not did 11yrs old <a href="http://www.xbench.com/">Xbench</a> or <a href="https://sourceforge.net/projects/jdiskmark/">jDiskMark beta</a> (written in Java).</p>
<p>In Ubuntu/Debian/RHEL land I&#8217;ve benchmarked device IO before and had good experience with FIO. FIO is a popular tool for measuring IOPS on a Linux servers. </p>
<blockquote><p>
<strong><br />
Do not make mistake of benchmarking (or using dd for eg.) /dev/disk device.<br />
On MacOS you should always use /dev/rdisk device.<br />
</strong></p>
<p><strong>/dev/disk</strong> &#8211; buffered access, for kernel filesystem calls, broken in 4kb chunks. goes more expensive root.<br />
<strong>/dev/rdisk</strong> &#8211; &#8220;raw&#8221; in the BSD sense and force block-aligned I/O. Those devices are closer to the physical disk than the buffered cache ones.<br />
If you do a read or write larger than one sector to /dev/rdisk, that request will be passed straight through. The lower layers may break it up (eg., USB breaks it up into 128KB pieces due to the maximum payload size in the USB protocol), but you generally can get bigger and more efficient I/Os. When streaming, like via dd, 128KB to 1MB are pretty good sizes to get near-optimal performance on current non-RAID hardware. (<a href="https://superuser.com/questions/631592/why-is-dev-rdisk-about-20-times-faster-than-dev-disk-in-mac-os-x">source</a>)</p>
</blockquote>
<p><strong>1. Install FIO</strong></p>
<pre class="brush: plain; title: ; notranslate">brew install fio</pre>
<p><strong>2. Check correct disk number</strong></p>
<pre class="brush: plain; title: ; notranslate">diskutil list</pre>
<p><strong>Everything from this step forward can and will delete data on your disk. So BE VERY CAREFUL on which disk you use.  You have been warned.</strong></p>
<p><strong>3. Precondition SSD</strong><br />
We precondition each drive the same way for each measurement, and stimulate the drive to the same performance state so the test process is deterministic</p>
<pre class="brush: plain; title: ; notranslate">sudo dd if=/dev/zero of=/dev/rdisk2 bs=1m</pre>
<p><strong>4. Running tests</strong></p>
<p><strong>Random read/write performance</strong></p>
<pre class="brush: plain; title: ; notranslate">./fio --randrepeat=1 --ioengine=posixaio --direct=1 --gtod_reduce=1 --name=test --filename=test --bs=4k --iodepth=64 --size=4G --readwrite=randrw --rwmixread=75</pre>
<p><strong>Random read performance</strong></p>
<pre class="brush: plain; title: ; notranslate">./fio --randrepeat=1 --ioengine=posixaio --direct=1 --gtod_reduce=1 --name=test --filename=test --bs=4k --iodepth=64 --size=4G --readwrite=randread</pre>
<p><strong>Random write performance</strong></p>
<pre class="brush: plain; title: ; notranslate">./fio --randrepeat=1 --ioengine=posixaio --direct=1 --gtod_reduce=1 --name=test --filename=test --bs=4k --iodepth=64 --size=4G --readwrite=randwrite</pre>
<p>(<em>On MacOS we must use posixaio ioengine. If you are on running some different flavour of Unix just replace &#8211;ioengine=<strong>posixaio</strong> with eg. &#8211;ioengine=<strong>libaio</strong> for Ubuntu</em>)</p>
<p><strong>5. The results</strong></p>
<p>The lady at the store was right! Using same HDD&#8217;s the cheaper HDD enclosure gave us better results. <strong>It was faster by almost 35%</strong>.</p>
<table border="1" cellpadding="5">
<tr style="font-weight: bold">
<td>tray</p>
<td>
<td>read mb/s</td>
<td>write mb/s</td>
<td>read IOPS</td>
<td>write IOPS</td>
</tr>
<tr>
<td>ASMT (/dev/disk)</p>
<td>
<td>10.9MiB/s</td>
<td>11.9MiB/s</td>
<td>86 IOPS</td>
<td>94 IOPS</td>
</tr>
<tr>
<td>ASMT</p>
<td>
<td>69.7MiB/s</td>
<td>72.8MiB/s</td>
<td>552 IOPS</td>
<td>576 IOPS</td>
</tr>
<tr>
<td>PATRIOT</p>
<td>
<td>92.4MiB/s</td>
<td>93.5MiB/s</td>
<td>738 IOPS</td>
<td>747 IOPS</td>
</tr>
</table>
<p>If you are interested in values I got, here there are.</p>
<p>The first set of benchmarks (done on buffered /dev/disk device) revealed really poor performance [r=10.9MiB/s,w=11.9MiB/s][r=86,w=94 IOPS].</p>
<pre class="brush: plain; title: ; notranslate">
sudo fio --filename=/dev/disk2 --direct=1 --rw=randrw --rwmixwrite=50 --refill_buffers --norandommap --randrepeat=0 --ioengine=posixaio --bs=128k --rate_iops=1280  --iodepth=16 --numjobs=1 --time_based --runtime=86400 --group_reporting --name=benchtest
fio-2.18
Starting 1 thread
^Cbs: 1 (f=1), 0-2560 IOPS: [m(1)][0.5%][r=10.9MiB/s,w=11.9MiB/s][r=86,w=94 IOPS][eta 23h:52m:35s]
fio: terminating on signal 2

benchtest: (groupid=0, jobs=1): err= 0: pid=3075: Fri Mar 24 20:14:55 2017
   read: IOPS=94, BW=11.8MiB/s (12.4MB/s)(5234MiB/445379msec)
    slat (usec): min=0, max=303, avg= 0.40, stdev= 2.28
    clat (msec): min=47, max=228, avg=100.40, stdev=14.81
     lat (msec): min=47, max=228, avg=100.40, stdev=14.81
    clat percentiles (msec):
     |  1.00th=[   74],  5.00th=[   82], 10.00th=[   85], 20.00th=[   90],
     | 30.00th=[   93], 40.00th=[   96], 50.00th=[   98], 60.00th=[  102],
     | 70.00th=[  105], 80.00th=[  111], 90.00th=[  119], 95.00th=[  127],
     | 99.00th=[  151], 99.50th=[  161], 99.90th=[  184], 99.95th=[  192],
     | 99.99th=[  208]
  write: IOPS=94, BW=11.8MiB/s (12.4MB/s)(5237MiB/445379msec)
    slat (usec): min=0, max=296, avg= 0.53, stdev= 2.81
    clat (msec): min=25, max=177, avg=69.66, stdev= 9.52
     lat (msec): min=25, max=177, avg=69.66, stdev= 9.52
    clat percentiles (msec):
     |  1.00th=[   51],  5.00th=[   58], 10.00th=[   61], 20.00th=[   63],
     | 30.00th=[   66], 40.00th=[   68], 50.00th=[   69], 60.00th=[   71],
     | 70.00th=[   73], 80.00th=[   76], 90.00th=[   80], 95.00th=[   86],
     | 99.00th=[  105], 99.50th=[  114], 99.90th=[  133], 99.95th=[  137],
     | 99.99th=[  151]
    lat (msec) : 50=0.44%, 100=76.81%, 250=22.76%
  cpu          : usr=0.46%, sys=0.41%, ctx=283619, majf=3, minf=6
  IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=50.0%, 16=50.0%, 32=0.0%, &gt;=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, &gt;=64=0.0%
     complete  : 0=0.0%, 4=98.3%, 8=1.7%, 16=0.1%, 32=0.0%, 64=0.0%, &gt;=64=0.0%
     issued rwt: total=41875,41894,0, short=0,0,0, dropped=0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=16

Run status group 0 (all jobs):
   READ: bw=11.8MiB/s (12.4MB/s), 11.8MiB/s-11.8MiB/s (12.4MB/s-12.4MB/s), io=5234MiB (5489MB), run=445379-445379msec
  WRITE: bw=11.8MiB/s (12.4MB/s), 11.8MiB/s-11.8MiB/s (12.4MB/s-12.4MB/s), io=5237MiB (5491MB), run=445379-445379msec
</pre>
<p>Repeated benchmark on same enclosure, but using raw device (/dev/rdisk) revealed much nicer numbers &#8211; 600% faster than buffered device<br />
[m(1)][0.3%][r=69.7MiB/s,w=72.8MiB/s][r=552,w=576 IOPS][eta 23h:55m:54s]</p>
<pre class="brush: plain; title: ; notranslate">
sudo fio --filename=/dev/rdisk2 --direct=1 --rw=randrw --rwmixwrite=50 --refill_buffers --norandommap --randrepeat=0 --ioengine=posixaio --bs=128k --rate_iops=1280  --iodepth=16 --numjobs=1 --time_based --runtime=86400 --group_reporting --name=benchtest
fio-2.18
Starting 1 thread
^Cbs: 1 (f=1), 0-2560 IOPS: [m(1)][0.3%][r=69.7MiB/s,w=72.8MiB/s][r=552,w=576 IOPS][eta 23h:55m:54s]
fio: terminating on signal 2

benchtest: (groupid=0, jobs=1): err= 0: pid=3075: Fri Mar 24 21:13:39 2017
   read: IOPS=538, BW=67.3MiB/s (70.6MB/s)(16.2GiB/245308msec)
    slat (usec): min=0, max=47, avg= 0.45, stdev= 1.02
    clat (msec): min=8, max=45, avg=15.05, stdev= 2.70
     lat (msec): min=8, max=45, avg=15.05, stdev= 2.70
    clat percentiles (usec):
     |  1.00th=[11200],  5.00th=[12224], 10.00th=[12736], 20.00th=[13376],
     | 30.00th=[13888], 40.00th=[14400], 50.00th=[14784], 60.00th=[15168],
     | 70.00th=[15680], 80.00th=[16320], 90.00th=[17280], 95.00th=[18048],
     | 99.00th=[23936], 99.50th=[36608], 99.90th=[39680], 99.95th=[40192],
     | 99.99th=[42240]
  write: IOPS=538, BW=67.4MiB/s (70.7MB/s)(16.2GiB/245308msec)
    slat (usec): min=0, max=65, avg= 0.46, stdev= 0.67
    clat (msec): min=6, max=45, avg=14.56, stdev= 2.71
     lat (msec): min=6, max=45, avg=14.57, stdev= 2.71
    clat percentiles (usec):
     |  1.00th=[10560],  5.00th=[11712], 10.00th=[12224], 20.00th=[12864],
     | 30.00th=[13376], 40.00th=[13888], 50.00th=[14272], 60.00th=[14784],
     | 70.00th=[15168], 80.00th=[15808], 90.00th=[16768], 95.00th=[17536],
     | 99.00th=[23680], 99.50th=[36096], 99.90th=[39168], 99.95th=[40192],
     | 99.99th=[42240]
    lat (msec) : 10=0.22%, 20=98.34%, 50=1.44%
  cpu          : usr=3.48%, sys=2.40%, ctx=531264, majf=3, minf=5
  IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=50.0%, 16=50.0%, 32=0.0%, &gt;=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, &gt;=64=0.0%
     complete  : 0=0.0%, 4=97.9%, 8=1.8%, 16=0.3%, 32=0.0%, 64=0.0%, &gt;=64=0.0%
     issued rwt: total=132027,132160,0, short=0,0,0, dropped=0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=16

Run status group 0 (all jobs):
   READ: bw=67.3MiB/s (70.6MB/s), 67.3MiB/s-67.3MiB/s (70.6MB/s-70.6MB/s), io=16.2GiB (17.4GB), run=245308-245308msec
  WRITE: bw=67.4MiB/s (70.7MB/s), 67.4MiB/s-67.4MiB/s (70.7MB/s-70.7MB/s), io=16.2GiB (17.4GB), run=245308-245308msec
</pre>
<p>Finally, the second HDD tray I benchmarked revealed best results, almost 35% faster than cheap-enclosure-1.<br />
[m(1)][0.5%][r=92.4MiB/s,w=93.5MiB/s][r=738,w=747 IOPS][eta 23h:52m:50s]</p>
<pre class="brush: plain; title: ; notranslate">
sudo fio --filename=/dev/rdisk3 --direct=1 --rw=randrw --rwmixwrite=50 --refill_buffers --norandommap --randrepeat=0 --ioengine=posixaio --bs=128k --rate_iops=1280  --iodepth=16 --numjobs=1 --time_based --runtime=86400 --group_reporting --name=benchtest
fio-2.18
Starting 1 thread
^Cbs: 1 (f=1), 0-2560 IOPS: [m(1)][0.5%][r=92.4MiB/s,w=93.5MiB/s][r=738,w=747 IOPS][eta 23h:52m:50s]
fio: terminating on signal 2

benchtest: (groupid=0, jobs=1): err= 0: pid=3075: Fri Mar 24 20:37:26 2017
   read: IOPS=761, BW=95.2MiB/s (99.8MB/s)(39.2GiB/430198msec)
    slat (usec): min=0, max=310, avg= 0.55, stdev= 2.23
    clat (msec): min=1, max=48, avg=11.43, stdev= 2.84
     lat (msec): min=1, max=48, avg=11.43, stdev= 2.84
    clat percentiles (usec):
     |  1.00th=[ 6880],  5.00th=[ 8256], 10.00th=[ 8896], 20.00th=[ 9536],
     | 30.00th=[10048], 40.00th=[10560], 50.00th=[11072], 60.00th=[11584],
     | 70.00th=[12224], 80.00th=[12864], 90.00th=[14016], 95.00th=[15296],
     | 99.00th=[22912], 99.50th=[28800], 99.90th=[35584], 99.95th=[37120],
     | 99.99th=[40704]
  write: IOPS=762, BW=95.3MiB/s (99.9MB/s)(40.3GiB/430198msec)
    slat (usec): min=0, max=767, avg= 0.96, stdev= 3.58
    clat (usec): min=492, max=45310, avg=9422.63, stdev=2869.71
     lat (usec): min=493, max=45311, avg=9423.59, stdev=2869.68
    clat percentiles (usec):
     |  1.00th=[ 5024],  5.00th=[ 6240], 10.00th=[ 6944], 20.00th=[ 7712],
     | 30.00th=[ 8256], 40.00th=[ 8640], 50.00th=[ 9024], 60.00th=[ 9536],
     | 70.00th=[10048], 80.00th=[10688], 90.00th=[11712], 95.00th=[13120],
     | 99.00th=[21888], 99.50th=[27264], 99.90th=[35072], 99.95th=[37120],
     | 99.99th=[40704]
    lat (usec) : 500=0.01%
    lat (msec) : 2=0.01%, 4=0.08%, 10=49.48%, 20=49.08%, 50=1.35%
  cpu          : usr=4.59%, sys=2.86%, ctx=1256049, majf=0, minf=11
  IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=57.4%, 16=42.6%, 32=0.0%, &gt;=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, &gt;=64=0.0%
     complete  : 0=0.0%, 4=98.2%, 8=1.8%, 16=0.1%, 32=0.0%, 64=0.0%, &gt;=64=0.0%
     issued rwt: total=327551,327861,0, short=0,0,0, dropped=0,0,0
     latency   : target=0, window=0, percentile=100.00%, depth=16

Run status group 0 (all jobs):
   READ: bw=95.2MiB/s (99.8MB/s), 95.2MiB/s-95.2MiB/s (99.8MB/s-99.8MB/s), io=39.2GiB (42.1GB), run=430198-430198msec
  WRITE: bw=95.3MiB/s (99.9MB/s), 95.3MiB/s-95.3MiB/s (99.9MB/s-99.9MB/s), io=40.3GiB (42.1GB), run=430198-430198msec
</pre>
<p><strong>Conclusion</strong><br />
fio is pretty robust utility for io testing. Beware of quality of onboard electronics when buying HDD trays. Trays within same price range, can vary 15-30% in speed.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2017/09/19/measuring-disk-io-performance-macos/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>What is MySQL STRAIGHT_JOIN and when to use it?</title>
		<link>https://www.nivas.hr/blog/2017/08/18/mysql-straight_join-use/</link>
					<comments>https://www.nivas.hr/blog/2017/08/18/mysql-straight_join-use/#respond</comments>
		
		<dc:creator><![CDATA[damir]]></dc:creator>
		<pubDate>Fri, 18 Aug 2017 14:48:05 +0000</pubDate>
				<category><![CDATA[developers journal]]></category>
		<category><![CDATA[mysql]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2801</guid>

					<description><![CDATA[I carefully hand-craft my SQL queries and check them with an EXPLAIN statement. So it came as a surprise that my highly optimized SQL query became so sloooow. After short investigation I discovered that MySQL optimizer changes the order in which tables are joined. In most cases the optimizer is right. In my case it...]]></description>
										<content:encoded><![CDATA[<p>I carefully hand-craft my SQL queries and check them with an <code>EXPLAIN</code> statement. So it came as a surprise that my highly optimized SQL query became so sloooow. After short investigation I discovered that MySQL optimizer changes the order in which tables are joined. In most cases the optimizer is right. In my case it was also right at the beginning of the project lifetime &#8211; but later it reordered them in suboptimal order.</p>
<p><a href="https://www.nivas.hr/blog/wp-content/uploads/2017/08/mysqlmeme.jpg"><img loading="lazy" class="aligncenter size-medium wp-image-2803" src="https://www.nivas.hr/blog/wp-content/uploads/2017/08/mysqlmeme-450x393.jpg" alt="" width="450" height="393" srcset="https://www.nivas.hr/blog/wp-content/uploads/2017/08/mysqlmeme-450x393.jpg 450w, https://www.nivas.hr/blog/wp-content/uploads/2017/08/mysqlmeme.jpg 500w" sizes="(max-width: 450px) 100vw, 450px" /></a></p>
<p>By using STRAIGHT_JOIN instead of &#8220;regular&#8221; inner join I made my sql query optimized again:</p>
<blockquote><p><code>STRAIGHT_JOIN</code> is an <strong>inner join</strong> where MySQL optimizer will not change the order of tables when joining them. It will always read the left table first and then the right table.</p></blockquote>
<p>In general, you should  put to the left  the table which would give smaller result set in the final result.</p>
<p>Since premature optimization is the root of all evil, you should use &#8220;regular&#8221; inner join, monitor you application performance and check <a href="https://dev.mysql.com/doc/refman/5.7/en/slow-query-log.html" target="_blank">MySQL slow log</a>. And if the sql query &#8220;suddenly&#8221; become slow &#8211; now you know how to fix it.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2017/08/18/mysql-straight_join-use/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Mysql GET_LOCK() “problem” … and how to debug it with help of mysql  performance_schema</title>
		<link>https://www.nivas.hr/blog/2017/08/04/mysql-get_lock-problem-debug-help-mysql-performance_schema/</link>
					<comments>https://www.nivas.hr/blog/2017/08/04/mysql-get_lock-problem-debug-help-mysql-performance_schema/#comments</comments>
		
		<dc:creator><![CDATA[damir]]></dc:creator>
		<pubDate>Fri, 04 Aug 2017 11:57:03 +0000</pubDate>
				<category><![CDATA[developers journal]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2778</guid>

					<description><![CDATA[After I recently switched back to Linux with php7 and mysql 5.7 I run into “bug” with MySQL GET_LOCK(). I executed php script which uses GET_LOCK(). Scripts were executed parallel (1-2s one after another) from two tabs of the same browser. According to the output, locking was not working!!! My first thought was that improvements...]]></description>
										<content:encoded><![CDATA[<p>After I recently switched back to Linux with php7 and mysql 5.7 I run into “bug” with MySQL GET_LOCK().<br />
I executed php script which uses GET_LOCK(). Scripts were executed parallel (1-2s one after another) from two tabs of the same browser.<br />
According to the output, locking was not working!!!</p>
<p><a href="https://www.nivas.hr/blog/wp-content/uploads/2017/08/programming-knock-knock.jpg"><img loading="lazy" class="aligncenter size-medium wp-image-2797" src="https://www.nivas.hr/blog/wp-content/uploads/2017/08/programming-knock-knock-450x450.jpg" alt="" width="450" height="450" srcset="https://www.nivas.hr/blog/wp-content/uploads/2017/08/programming-knock-knock-450x450.jpg 450w, https://www.nivas.hr/blog/wp-content/uploads/2017/08/programming-knock-knock-150x150.jpg 150w, https://www.nivas.hr/blog/wp-content/uploads/2017/08/programming-knock-knock-480x480.jpg 480w, https://www.nivas.hr/blog/wp-content/uploads/2017/08/programming-knock-knock.jpg 500w" sizes="(max-width: 450px) 100vw, 450px" /></a></p>
<p>My first thought was that improvements which were introduced in MySQL 5.7. regarding GET_LOCK() broke something.</p>
<p>Test script:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

$host = 'DB_HOST';
$db   = 'DB_NAME';
$user = 'DB_USER';
$pass = 'DB_PASSWD';
$charset = 'utf8mb4';

$dsn = &quot;mysql:host=$host;dbname=$db;charset=$charset&quot;;
$opt = [
    PDO::ATTR_ERRMODE            =&gt; PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE =&gt; PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   =&gt; false,
	PDO::ATTR_PERSISTENT =&gt; false
];
$pdo = new PDO($dsn, $user, $pass, $opt);

echo &quot;&lt;pre&gt;&quot;;
echo &quot;pid=(&quot;.getmypid().&quot;)\n&quot;;

$stmt = $pdo-&gt;query('SELECT GET_LOCK(&quot;foobar&quot;, 15)');
$row = $stmt-&gt;fetch();

var_dump($row);
echo &quot;\n&quot;;

echo &quot;Sleep for 50s\n&quot;;
sleep(50);

echo &quot;&lt;/pre&gt;&quot;;
?&gt;
</pre>
<p>Lock timeout is 15s and script executes (and hold lock) for 50s so I could have time to start both scripts in parallel and monitor MySQL performance_schema.</p>
<p>Result from the first tab:</p>
<pre class="brush: plain; title: ; notranslate">
pid=(14769)
array(1) {
  [&quot;GET_LOCK(&quot;foobar&quot;, 15)&quot;]=&gt;
  int(1)
}

Sleep for 50s
</pre>
<p>Result from the second tab:</p>
<pre class="brush: plain; title: ; notranslate">
pid=(14769)
array(1) {
  [&quot;GET_LOCK(&quot;foobar&quot;, 15)&quot;]=&gt;
  int(1)
}

Sleep for 50s
</pre>
<p>Output is not as expected. GET_LOCK() from the second tab should return 0, not 1.</p>
<p>I executed the script again, but from the command line, again in parallel. Second one was executed 1-2s after the first one.</p>
<p>Result from the first (cmd line):</p>
<pre class="brush: plain; title: ; notranslate">
$ php -q locktest_1.php 

&lt;pre&gt;pid=(16328)
array(1) {
  [&quot;GET_LOCK(&quot;foobar&quot;, 15)&quot;]=&gt;
  int(1)
}

Sleep for 50s
</pre>
<p>Result from the second (cmd line):</p>
<pre class="brush: plain; title: ; notranslate">
$ php -q locktest_1.php 

&lt;pre&gt;pid=(16382)
array(1) {
  [&quot;GET_LOCK(&quot;foobar&quot;, 15)&quot;]=&gt;
  int(0)
}

Sleep for 50s
</pre>
<p>And everything was working as expected. First script obtained the lock, and second didn&#8217;t.</p>
<p>With helpful comments from StackOverflow community I continued with my investigation.</p>
<h2>Put the performance_schema to good use</h2>
<p>In order to see what is happening with my locks it is necessary to monitor performance_schema.threads and performance_schema.metadata_locks closely. To learn more about it check the <a href="https://dev.mysql.com/doc/refman/5.5/en/performance-schema.html" target="_blank">MySQL documentation</a>.</p>
<p>I added <a href="https://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_connection-id" target="_blank">connection_id()</a> in php test script in order to match running php script with entries in the performance_schema.threads and performance_schema.metadata_locks tables.</p>
<h2>Second round of tests</h2>
<p>Now, armed with all this data, second round of test can begin.</p>
<p>After running the test scripts I quickly executed these sql queries:</p>
<pre class="brush: sql; title: ; notranslate">
select * from performance_schema.threads;
</pre>
<pre class="brush: sql; title: ; notranslate">
select * from performance_schema.metadata_locks;
</pre>
<p>You will see active threads and locks and their status (GRANTED, PENDING).</p>
<p>First one returned:</p>
<pre class="brush: plain; title: ; notranslate">
pid=(14773)
CONNECTION_ID()=(71)
array(1) {
  [&quot;GET_LOCK(&quot;foobar&quot;, 15)&quot;]=&gt;
  int(1)
}
Sleep for 50s
</pre>
<p>Second one returned:</p>
<pre class="brush: plain; title: ; notranslate">
pid=(14773)
CONNECTION_ID()=(72)
array(1) {
  [&quot;GET_LOCK(&quot;foobar&quot;, 15)&quot;]=&gt;
  int(1)
}
Sleep for 50s
</pre>
<p>Also in performance_schema.threads there was at any point in time only one entry related to the test script.<br />
First it showed:</p>
<p><a href="https://www.nivas.hr/blog/wp-content/uploads/2017/08/01_blog_post_processlist_id_71_Selection_042.jpg"><img loading="lazy" class="aligncenter size-medium wp-image-2794" src="https://www.nivas.hr/blog/wp-content/uploads/2017/08/01_blog_post_processlist_id_71_Selection_042-450x51.jpg" alt="" width="450" height="51" srcset="https://www.nivas.hr/blog/wp-content/uploads/2017/08/01_blog_post_processlist_id_71_Selection_042-450x51.jpg 450w, https://www.nivas.hr/blog/wp-content/uploads/2017/08/01_blog_post_processlist_id_71_Selection_042-768x88.jpg 768w, https://www.nivas.hr/blog/wp-content/uploads/2017/08/01_blog_post_processlist_id_71_Selection_042-1024x117.jpg 1024w" sizes="(max-width: 450px) 100vw, 450px" /></a></p>
<p>Please note row with PROCESSLIST_ID = 71 (matching the output from the first script)</p>
<p>I kept refreshing performance_schema.threads and noticed that one thread related to the test script was replaced with another one. They were not running in parallel like they do when I start test script from cmd line.</p>
<p><a href="https://www.nivas.hr/blog/wp-content/uploads/2017/08/02_blog_post_proccesslist_id_72_Selection_043.jpg"><img loading="lazy" class="aligncenter size-medium wp-image-2793" src="https://www.nivas.hr/blog/wp-content/uploads/2017/08/02_blog_post_proccesslist_id_72_Selection_043-450x49.jpg" alt="" width="450" height="49" srcset="https://www.nivas.hr/blog/wp-content/uploads/2017/08/02_blog_post_proccesslist_id_72_Selection_043-450x49.jpg 450w, https://www.nivas.hr/blog/wp-content/uploads/2017/08/02_blog_post_proccesslist_id_72_Selection_043-768x83.jpg 768w, https://www.nivas.hr/blog/wp-content/uploads/2017/08/02_blog_post_proccesslist_id_72_Selection_043-1024x111.jpg 1024w" sizes="(max-width: 450px) 100vw, 450px" /></a></p>
<p>Please note row with PROCESSLIST_ID = 72 (matching the output from the second script)<br />
Also performance_schema.metadata_locks showed only one lock at any point in time (not one GRANTED and one PENDING):</p>
<p><a href="https://www.nivas.hr/blog/wp-content/uploads/2017/08/02_blog_post_thread_96.jpg"><img loading="lazy" class="aligncenter size-medium wp-image-2792" src="https://www.nivas.hr/blog/wp-content/uploads/2017/08/02_blog_post_thread_96-450x46.jpg" alt="" width="450" height="46" srcset="https://www.nivas.hr/blog/wp-content/uploads/2017/08/02_blog_post_thread_96-450x46.jpg 450w, https://www.nivas.hr/blog/wp-content/uploads/2017/08/02_blog_post_thread_96-768x79.jpg 768w, https://www.nivas.hr/blog/wp-content/uploads/2017/08/02_blog_post_thread_96-1024x106.jpg 1024w, https://www.nivas.hr/blog/wp-content/uploads/2017/08/02_blog_post_thread_96.jpg 1501w" sizes="(max-width: 450px) 100vw, 450px" /></a></p>
<p>For example, when script was executed in parallel from cmd line performance_schema.metadata_locks showed:</p>
<p><a href="https://www.nivas.hr/blog/wp-content/uploads/2017/08/Selection_044.jpg"><img loading="lazy" class="aligncenter size-medium wp-image-2795" src="https://www.nivas.hr/blog/wp-content/uploads/2017/08/Selection_044-450x48.jpg" alt="" width="450" height="48" srcset="https://www.nivas.hr/blog/wp-content/uploads/2017/08/Selection_044-450x48.jpg 450w, https://www.nivas.hr/blog/wp-content/uploads/2017/08/Selection_044-768x82.jpg 768w, https://www.nivas.hr/blog/wp-content/uploads/2017/08/Selection_044-1024x110.jpg 1024w, https://www.nivas.hr/blog/wp-content/uploads/2017/08/Selection_044.jpg 1531w" sizes="(max-width: 450px) 100vw, 450px" /></a></p>
<p>For now, it seems that locking is in fact working correctly, but the scripts executed from two tabs of the same browser are not being executed in parallel.</p>
<h2>Third round of tests</h2>
<p>I upgraded the test script to show start timestamp and end timestamp. This also proved that although I started the scripts with 1-2s delay, that they in fact were not running at the same time.</p>
<p>Final test script:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

$host = 'DB_HOST';
$db   = 'DB_NAME';
$user = 'DB_USER';
$pass = 'DB_PASSWD';
$charset = 'utf8mb4';

$dsn = &quot;mysql:host=$host;dbname=$db;charset=$charset&quot;;
$opt = [
    PDO::ATTR_ERRMODE            =&gt; PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE =&gt; PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   =&gt; false,
	PDO::ATTR_PERSISTENT =&gt; false
];
$pdo = new PDO($dsn, $user, $pass, $opt);

echo &quot;&lt;pre&gt;&quot;;

echo &quot;start timestamp=(&quot;.date(&quot;c&quot;).&quot;)\n&quot;;

echo &quot;pid=(&quot;.getmypid().&quot;)\n&quot;;

$stmt = $pdo-&gt;query('SELECT CONNECTION_ID() as connid');
$row = $stmt-&gt;fetch();

echo &quot;CONNECTION_ID()=(&quot;.$row['connid'].&quot;)\n&quot;;

$stmt = $pdo-&gt;query('SELECT GET_LOCK(&quot;foobar&quot;, 15)');
$row = $stmt-&gt;fetch();

var_dump($row);
echo &quot;\n&quot;;

echo &quot;Sleep for 50s\n&quot;;
sleep(50);

echo &quot;end timestamp=(&quot;.date(&quot;c&quot;).&quot;)\n&quot;;
echo &quot;&lt;/pre&gt;&quot;;
?&gt;
</pre>
<p>First one returned:</p>
<pre class="brush: plain; title: ; notranslate">
start timestamp=(2017-08-03T14:30:48+00:00)
pid=(14768)
CONNECTION_ID()=(73)
array(1) {
  [&quot;GET_LOCK(&quot;foobar&quot;, 15)&quot;]=&gt;
  int(1)
}
Sleep for 50s
end timestamp=(2017-08-03T14:31:38+00:00)
</pre>
<p>Second one returned:</p>
<pre class="brush: plain; title: ; notranslate">
start timestamp=(2017-08-03T14:31:38+00:00)
pid=(14768)
CONNECTION_ID()=(74)
array(1) {
  [&quot;GET_LOCK(&quot;foobar&quot;, 15)&quot;]=&gt;
  int(1)
}
Sleep for 50s
end timestamp=(2017-08-03T14:32:28+00:00)
</pre>
<p>Please note the end timestamp of the first and start timestamp of the second script.</p>
<h2>Conclusion</h2>
<p>Execution of the scripts was serialized. They definitely didn&#8217;t run in parallel and that was the reason why both succeeded to acquire the lock.</p>
<p>GET_LOCK() in MySQL 5.7 is still working as it should (plus the improvements). But even more important, I realized what a powerful tool Performance Schema is in debugging what at first appeared to be really weird bug.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2017/08/04/mysql-get_lock-problem-debug-help-mysql-performance_schema/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Recursions and PHP</title>
		<link>https://www.nivas.hr/blog/2017/08/02/recursions-and-php/</link>
					<comments>https://www.nivas.hr/blog/2017/08/02/recursions-and-php/#respond</comments>
		
		<dc:creator><![CDATA[Luka U.]]></dc:creator>
		<pubDate>Wed, 02 Aug 2017 11:31:01 +0000</pubDate>
				<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2713</guid>

					<description><![CDATA[Introduction Recursion occurs when something uses a similar version of itself. Recursive procedure is one where at least one of its’ steps calls for a new instance of that very same procedure (broadly speaking we say that function calls itself). It is similar to iteration, with one major difference – iteration requires predefined number of...]]></description>
										<content:encoded><![CDATA[<h4>Introduction</h4>
<p style="text-align: left">Recursion occurs when something uses a similar version of itself. Recursive procedure is one where at least one of its’ steps calls for a new instance of that very same procedure (broadly speaking we say that function calls itself). It is similar to iteration, with one major difference – iteration requires predefined number of repetitions, and with recursion one doesn’t need to know in advance how many repetitions there will be. In order to limit the number of repetitions and to avoid or stack overflow there must be a terminating scenario defined, so that the procedure can complete.</p>
<p style="text-align: left"><a href="https://www.nivas.hr/blog/wp-content/uploads/2017/08/db20539b342f1f578151061b27e636aaf6cd48b6e58e28327877f7b724dd79dd-1.jpg"><img loading="lazy" class="alignnone size-full wp-image-2768" src="https://www.nivas.hr/blog/wp-content/uploads/2017/08/db20539b342f1f578151061b27e636aaf6cd48b6e58e28327877f7b724dd79dd-1.jpg" alt="" width="339" height="431" /></a></p>
<p>PHP limits the number of recursive calls and but it&#8217;s possible to expand this limit in php.ini file options.</p>
<p><a href="https://www.nivas.hr/blog/wp-content/uploads/2017/07/Screenshot-from-2017-07-28-10-09-23.png"><img loading="lazy" class="alignnone size-medium wp-image-2714" src="https://www.nivas.hr/blog/wp-content/uploads/2017/07/Screenshot-from-2017-07-28-10-09-23-450x107.png" alt="" width="450" height="107" srcset="https://www.nivas.hr/blog/wp-content/uploads/2017/07/Screenshot-from-2017-07-28-10-09-23-450x107.png 450w, https://www.nivas.hr/blog/wp-content/uploads/2017/07/Screenshot-from-2017-07-28-10-09-23-768x183.png 768w, https://www.nivas.hr/blog/wp-content/uploads/2017/07/Screenshot-from-2017-07-28-10-09-23.png 997w" sizes="(max-width: 450px) 100vw, 450px" /></a></p>
<p><a href="http://php.net/manual/en/pcre.configuration.php" target="_blank">http://php.net/manual/en/pcre.configuration.php</a></p>
<p>All recursive algorithms must have the following:</p>
<p style="padding-left: 30px">1. Base Case &#8211; end condition which is the solution to the &#8220;simplest&#8221; possible problem</p>
<p style="padding-left: 30px">2. Work toward Base Case &#8211; making the problem simpler</p>
<p style="padding-left: 30px">3. Recursive Call &#8211; using the same algorithm to solve a simpler instance of the problem</p>
<p>In order to show on a simple example how recursion works we will use the factorials. In mathematics, the factorial of a non-negative integer n, denoted by n!, is the product of all positive integers less than or equal to n. For example: 5! = 5 * 4 * 3 * 2 * 1 = 120. Let’s write two simple algorithms to calculate the factorial value of given integer.</p>
<p>The first example will use iterative approach:</p>
<pre class="brush: php; title: ; notranslate">
$number = 5;
function iterativeFactorial($number)
{
 if ($number &lt; 0) {
 return -1; //initial condition, if number is negative exit the program
 }
 else if ($number === 0) {
 return 1; //factorial of 0 is 1
 }

 $factorial = 1;

 if ($number &lt;= 1) return $factorial;
 while ($number &gt; 1) {
 $factorial *= $number;
 $number--;
 }
 return $factorial;

}
</pre>
<p>The second example will use recursive approach:</p>
<pre class="brush: php; title: ; notranslate">
$number = 5;

function recursiveFactorial($number)
{
 if($number &lt; 0) {
 return -1; //initial condition, if number is negative exit the program
 }
 else if($number === 0) {
 return 1; //base case to exit the recursion
 } else {
 return $number * recursiveFactorial($number-1); // recursive call
 }
}
</pre>
<h4>How It works</h4>
<h5>Phase One &#8211; creating new instances and saving them on stack</h5>
<p>This phase is characterized by creating new instances of function calls and storing them on stack together with their addresses. In the first call the variable equals to 5 ($number = 5). It goes through initial condition &#8211; number must be positive in order to continue down the function. Then the base condition in which if number equals to zero the function will exit recursion. If this doesn’t happen ($number &gt; 0), the function will call itself recursively to derive new instance of itself &#8211; 5 * recursiveFactorial( 5 &#8211; 1 ). The first instance of the function will wait on stack while the new instance repeats the process, this time $number variable will be equal to 5 – 1, which is 4 and it will compute 4 * recursiveFactorial (3). The process will continue until the $number variable is zero, in which case the function will return 1 and won’t call for the new instance of itself (base condition). At this point all created instances are waiting on stack, together with their return addresses.</p>
<h5>Phase Two &#8211; Computing and deleting created instances from stack</h5>
<p>The returning of 1 wakes up the last created instance of the function on stack (the one that called It &#8211; $number = 1), which accepts the return value of 1 and uses it to compute 1 * recursiveFactorial(1-1). This returns 1, the called instance is being deleted from stack and the next instance on stack is being called ($number = 2). After computing 2 * recursiveFactorial(2-1), 2 is returned, the called instance is being deleted from stack and next instance on stack is being called. The process continues until the “oldest” instance of function (the first one to be stored on stack, $number = 5) is computed and the final value of 120 returned.</p>
<p><a href="https://www.nivas.hr/blog/wp-content/uploads/2017/07/recursive_f_stack.png"><img loading="lazy" src="https://www.nivas.hr/blog/wp-content/uploads/2017/07/recursive_f_stack-450x324.png" alt="" width="450" height="324" /></a></p>
<h4>Simple test</h4>
<p>Both functions were ran as php files from command line, using Ubuntu on my laptop. The $number variable was set to 150 and each function was ran 3 times.  The results showed that on average recursive approach needed approximately 3.7 times more time than iterative.</p>
<h4>Conclusion</h4>
<p>The main disadvantage of recursive approach is that the algorithm may require large amounts of memory if the recursion goes very deep. This is because when the function is called, a new instance is created in memory.  Also, it will most likely consume more time than iterative. Both disadvantages can be minimized with tail optimization which is not supported in PHP.</p>
<p>However there are pros to using recursive approach. It is more elegant and makes code more readable. Because of that it can reduce time needed to write and debug code. This approach is more suitable for solving specific problems, when problem can be broken down into smaller pieces (such as sorting algorithms).</p>
<p>The ultimate goal should always be to get as close as possible to achieving ‘low memory consumption and short execution time’. It’s up to a programmer to decide which approach works better for a specific problem in a specific development environment.</p>
<h4></h4>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2017/08/02/recursions-and-php/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>C# Delegates and Events</title>
		<link>https://www.nivas.hr/blog/2017/06/08/csharp-delegates-and-events/</link>
					<comments>https://www.nivas.hr/blog/2017/06/08/csharp-delegates-and-events/#respond</comments>
		
		<dc:creator><![CDATA[damir]]></dc:creator>
		<pubDate>Thu, 08 Jun 2017 16:30:20 +0000</pubDate>
				<category><![CDATA[c#]]></category>
		<category><![CDATA[developers journal]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[delegate]]></category>
		<category><![CDATA[delegates]]></category>
		<category><![CDATA[event]]></category>
		<category><![CDATA[events]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2598</guid>

					<description><![CDATA[When I started learning C# the difference and relation between delegate and event was not so clear to me. After checking few books and lots of googling I realized that I am not the only one. :) Some resources were correct in their description but lacked the comprehensive examples, other were completely wrong or just...]]></description>
										<content:encoded><![CDATA[<p>When I started learning C# the difference and relation between delegate and event was not so clear to me. After checking few books and lots of googling I realized that I am not the only one. :)</p>
<p>Some resources were correct in their description but lacked the comprehensive examples, other were completely wrong or just very unclear.</p>
<p>In this article the same task will be implemented using only delegate, and then using both delegate and event. So the difference, relation between delegate and event and the advantage of using the event will be clear.</p>
<p>It is expected that reader of this article is familiar with basic C# and has <em>some</em> knowledge about delegates and events.</p>
<h2>Delegate</h2>
<blockquote><p>A delegate is a type that represents references to methods with a particular parameter list and return type. When you instantiate a delegate, you can associate its instance with any method with a compatible signature and return type. You can invoke (or call) the method through the delegate instance.</p>
<p><a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/">https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/</a></p></blockquote>
<p>Please note that delegates can be chained – on single call multiple methods will be called.</p>
<h2>Event</h2>
<blockquote><p>Events enable a class or object to notify other classes or objects when something of interest occurs. The class that sends (or raises) the event is called the publisher and the classes that receive (or handle) the event are called subscribers.</p>
<p><a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/events/">https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/events/</a></p></blockquote>
<h2>Task</h2>
<p>We will create one lemming and three watchers that will monitor its health and respond as soon as health changes.</p>
<h2>Delegate example</h2>
<pre class="brush: csharp; title: ; notranslate">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace delegate_only
{
	public delegate void LemmingChanged(Lemming lemming);

	public class Lemming
	{
		private int health;

		public int Health
		{
			get { return health; }
			set
			{
				health = value;

				if (LemmingChanged != null)
				{
					LemmingChanged(this);
				}
			}
		}

		public LemmingChanged LemmingChanged;
	}

	class LemmingWatch
	{
		public void LemmingChangedHandler(Lemming lemming)
		{
			Console.WriteLine($&quot;LemmingWatch lemming changed. Health=({lemming.Health})&quot;);
		}
	}

	class AnotherLemmingWatch
	{
		public void LemmingChangedHandler(Lemming Lemming)
		{
			Console.WriteLine($&quot;AnotherLemmingWatch Lemming changed. Health=({Lemming.Health})&quot;);
		}
	}

	class YetAnotherLemmingWatch
	{
		public void LemmingChangedHandler(Lemming Lemming)
		{
			Console.WriteLine($&quot;YetAnotherLemmingWatch Lemming changed. Health=({Lemming.Health})&quot;);
		}
	}

	class Program
	{
		static void Main(string[] args)
		{
			Lemming Lemming = new Lemming() { Health = 99 };

			LemmingWatch LemmingWatch = new LemmingWatch();
			AnotherLemmingWatch anotherLemmingWatch = new AnotherLemmingWatch();

			Lemming.LemmingChanged += LemmingWatch.LemmingChangedHandler;
			Lemming.LemmingChanged += anotherLemmingWatch.LemmingChangedHandler;

			Console.WriteLine(&quot;Change Health:&quot;);
			Lemming.Health = 80;

			Console.WriteLine(&quot;\n--\n&quot;);

			// LemmingChanged not encapsulated 
			Console.WriteLine(&quot;LemmingChanged not encapsuled: Loose previous chained methods by mistake:&quot;);

			YetAnotherLemmingWatch yetAnotherLemmingWatching = new YetAnotherLemmingWatch();
			Lemming.LemmingChanged = yetAnotherLemmingWatching.LemmingChangedHandler; // loosing previous chained methods - mistake '=' instead of '+='
			Console.WriteLine(&quot;Change Health:&quot;);
			Lemming.Health = 51;
			

			Console.ReadLine();
		}
	}
}
</pre>
<h3>Output</h3>
<pre>Change Health:
LemmingWatch lemming changed. Health=(80)
AnotherLemmingWatch Lemming changed. Health=(80)

--

LemmingChanged not encapsuled: Loose previous chained methods by mistake:
Change Health:
YetAnotherLemmingWatch Lemming changed. Health=(51)</pre>
<p>As you can see delegate is public – for now, this is necessary in order to enable adding event handler from outside of the class.</p>
<pre class="brush: csharp; title: ; notranslate">
public LemmingChanged LemmingChanged;
</pre>
<p>Two event handlers are successfully added:</p>
<pre class="brush: csharp; title: ; notranslate">
Lemming.LemmingChanged += LemmingWatch.LemmingChangedHandler;
Lemming.LemmingChanged += anotherLemmingWatch.LemmingChangedHandler;
</pre>
<p>But there is mistake when adding the third one – and two previously added event handlers are removed by simple typing mistake (= instead of +=):</p>
<pre class="brush: csharp; title: ; notranslate">
Lemming.LemmingChanged = yetAnotherLemmingWatching.LemmingChangedHandler;
</pre>
<p>Also since delegate is public – it is possible to evoke the event from the outside of the class and evoke event handlers although requirements for raising the event are not met.</p>
<h2>Event example</h2>
<pre class="brush: csharp; title: ; notranslate">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace delegate_with_event
{
	public delegate void LemmingChanged(Lemming lemming);

	public class Lemming
	{
		private int health;

		public int Health
		{
			get { return health; }
			set
			{
				health = value;

				if (lemmingChanged != null)
				{
					lemmingChanged(this); // use private delegate
				}
			}
		}

		private LemmingChanged lemmingChanged; // changed to private

		// use event to add and remove event handler to/from delegate
		public event LemmingChanged LemmingChanged
		{
			add
			{
				lemmingChanged += value;
			}
			remove
			{
				lemmingChanged -= value;
			}

		}


	}

	class LemmingWatch
	{
		public void LemmingChangedHandler(Lemming lemming)
		{
			Console.WriteLine($&quot;LemmingWatch lemming changed. Health=({lemming.Health})&quot;);
		}
	}

	class AnotherLemmingWatch
	{
		public void LemmingChangedHandler(Lemming Lemming)
		{
			Console.WriteLine($&quot;AnotherLemmingWatch Lemming changed. Health=({Lemming.Health})&quot;);
		}
	}

	class YetAnotherLemmingWatch
	{
		public void LemmingChangedHandler(Lemming Lemming)
		{
			Console.WriteLine($&quot;YetAnotherLemmingWatch Lemming changed. Health=({Lemming.Health})&quot;);
		}
	}

	class Program
	{
		static void Main(string[] args)
		{
			Lemming Lemming = new Lemming() { Health = 99 };

			LemmingWatch LemmingWatch = new LemmingWatch();
			AnotherLemmingWatch anotherLemmingWatch = new AnotherLemmingWatch();

			Lemming.LemmingChanged += LemmingWatch.LemmingChangedHandler;
			Lemming.LemmingChanged += anotherLemmingWatch.LemmingChangedHandler;

			Console.WriteLine(&quot;Change Health:&quot;);
			Lemming.Health = 80;

			Console.WriteLine(&quot;\n--\n&quot;);

			// LemmingChanged not encapsulated 
			Console.WriteLine(&quot;Add 3rd event handler:&quot;);

			YetAnotherLemmingWatch yetAnotherLemmingWatching = new YetAnotherLemmingWatch();
			// impossible to make mistake: C# error: event Lemming.LemmingChanged can only appear on the left hand side of += -=
			//Lemming.LemmingChanged = yetAnotherLemmingWatching.LemmingChangedHandler; 
			Lemming.LemmingChanged += yetAnotherLemmingWatching.LemmingChangedHandler;
			Console.WriteLine(&quot;Change Health:&quot;);
			Lemming.Health = 51;


			Console.ReadLine();
		}
	}
}
</pre>
<h3>Output</h3>
<pre> Change Health:
 LemmingWatch lemming changed. Health=(80)
 AnotherLemmingWatch Lemming changed. Health=(80)

--

Add 3rd event handler:
 Change Health:
 LemmingWatch lemming changed. Health=(51)
 AnotherLemmingWatch Lemming changed. Health=(51)
 YetAnotherLemmingWatch Lemming changed. Health=(51)</pre>
<p>Delegate is now private:</p>
<pre class="brush: csharp; title: ; notranslate">
private LemmingChanged lemmingChanged;
</pre>
<p>Using event to add or remove event handler to or from delegate is very similar as using properties to get and set value to member variables.</p>
<p>Just instead of set/get,  add/remove is used. :)</p>
<pre class="brush: csharp; title: ; notranslate">
public event LemmingChanged LemmingChanged
{
	add
	{
		lemmingChanged += value;
	}
	remove
	{
		lemmingChanged -= value;
	}
}
</pre>
<p>Adding and removing the event handlers is done through event. It is not possible to access delegate directly from outside of the class.</p>
<p>And if we try to clear previously added event handlers by using = instead of += as in previous example &#8211; it is just not possible:</p>
<pre class="brush: csharp; title: ; notranslate">
Lemming.LemmingChanged = yetAnotherLemmingWatching.LemmingChangedHandler; 
</pre>
<p>C# will report error:</p>
<blockquote><p>event Lemming.LemmingChanged can only appear on the left hand side of += -=</p></blockquote>
<h2>Conclusion</h2>
<p>Events are heavily relay on delegates. In fact relationship between events and delegates is very similar as relationship between properties and member variables. Events provide safe and friendly way of using delegates.</p>
<p>They enable adding and removing event handlers from the outside of the class without allowing bad things to happen. Using events it is not possible to clear all event handlers by mistake or to raise the event from outside of the class (this is important because it is class responsibility to invoke the delegate when some class internal conditions are met).</p>
<p>By using events as a &#8220;wrapper&#8221; for delegate you encapsulation is not broken and you keep the needed flexibility. You can have you cake an eat it. :)<br />
<a href="https://www.nivas.hr/blog/wp-content/uploads/2017/06/kolac.jpg"><img loading="lazy" class="aligncenter wp-image-2629" src="https://www.nivas.hr/blog/wp-content/uploads/2017/06/kolac-450x194.jpg" alt="" width="517" height="223" srcset="https://www.nivas.hr/blog/wp-content/uploads/2017/06/kolac-450x194.jpg 450w, https://www.nivas.hr/blog/wp-content/uploads/2017/06/kolac-768x331.jpg 768w, https://www.nivas.hr/blog/wp-content/uploads/2017/06/kolac.jpg 999w" sizes="(max-width: 517px) 100vw, 517px" /></a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2017/06/08/csharp-delegates-and-events/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Install vpnc on MacOS Sierra</title>
		<link>https://www.nivas.hr/blog/2017/02/15/install-vpnc-macos-sierra/</link>
					<comments>https://www.nivas.hr/blog/2017/02/15/install-vpnc-macos-sierra/#comments</comments>
		
		<dc:creator><![CDATA[seven]]></dc:creator>
		<pubDate>Wed, 15 Feb 2017 14:06:10 +0000</pubDate>
				<category><![CDATA[apple]]></category>
		<category><![CDATA[developers journal]]></category>
		<category><![CDATA[macos]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2564</guid>

					<description><![CDATA[Update: 3.4.2017. this no longer works since homebrew/boneyard got obsoleted/deleted today. If you try to install Cisco VPN concentrator client (vpnc) today, chances are you won&#8217;t be able to since it was removed from regular homebrew formulae. However you can still install it from archive of homebrew formulae (boneyard): Be aware that this version of...]]></description>
										<content:encoded><![CDATA[<p><strong>Update: 3.4.2017. this no longer works since homebrew/boneyard got obsoleted/deleted today.</strong></p>
<p>If you try to install Cisco VPN concentrator client (vpnc) today, chances are you won&#8217;t be able to since it was removed from regular homebrew formulae.</p>
<pre class="brush: plain; title: ; notranslate">
brew install vpnc
Error: No available formula with the name &quot;vpncc&quot;
==&gt; Searching for similarly named formulae...
Error: No similarly named formulae found.
==&gt; Searching taps...
Error: No formulae found in taps.
</pre>
<p>However you can still install it from <a href="https://github.com/Homebrew/homebrew-boneyard">archive</a> of homebrew formulae (boneyard):</p>
<pre class="brush: plain; title: ; notranslate">
brew cask install tuntap
brew install homebrew/boneyard/vpnc
</pre>
<p>Be aware that this version of vpnc requires tuntap installed, also, it installs all this as dependencies:</p>
<pre class="brush: plain; title: ; notranslate">
brew deps vpnc
gmp
gnutls
libffi
libgcrypt
libgpg-error
libtasn1
libunistring
nettle
p11-kit
</pre>
<p>This will install <a href="https://www.unix-ag.uni-kl.de/~massar/vpnc/">last available</a>, rather old vpnc version 0.5.3 dating back in 2006.</p>
<p>I found a <a href="https://brianreiter.org/2014/12/03/i-modified-vpnc-cisco-vpn-client-to-use-os-x-user-native-tunnels/">new and modified version of vpnc</a> on <a href="https://github.com/breiter/vpnc">github</a> modified for xnu (OS X 10.6+) and  utun support so tuntap is not required. Unfortunately it is not yet in brew as formulae. However if you install all above dependencies, you will be able to build it easily your self:</p>
<pre class="brush: plain; title: ; notranslate">
git clone https://github.com/breiter/vpnc.git
cd vpnc
make
sudo make install
</pre>
<p>This will install vpnc version 0.5.3-xnu-2015-07-03.</p>
<p>Both vpnc versions expect configuration to be present in </p>
<pre class="brush: plain; title: ; notranslate">
/usr/local/etc/vpnc
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2017/02/15/install-vpnc-macos-sierra/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Apache sending &#8220;Vary: Host&#8221; making things uncacheable for Varnish</title>
		<link>https://www.nivas.hr/blog/2017/02/13/apache-sending-vary-host-making-things-uncacheable-varnish/</link>
					<comments>https://www.nivas.hr/blog/2017/02/13/apache-sending-vary-host-making-things-uncacheable-varnish/#respond</comments>
		
		<dc:creator><![CDATA[seven]]></dc:creator>
		<pubDate>Mon, 13 Feb 2017 22:36:02 +0000</pubDate>
				<category><![CDATA[developers journal]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[varnish]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2530</guid>

					<description><![CDATA[TLDR; Using %{HTTP_HOST} in .htaccess, will cause Apache to included a “Vary: Host” field in response. Subsequently &#8220;Vary: Host&#8221; header from Apache will force Varnish not to cache otherwise cacheable content. HTTP Vary is not a trivial concept. It is by far the most misunderstood HTTP header. (Varnish Docs) On a project I&#8217;ve been working,...]]></description>
										<content:encoded><![CDATA[<p><strong>TLDR;<br />
Using <em>%{HTTP_HOST}</em> in <em>.htaccess</em>, will cause Apache to included a <em>“Vary: Host”</em> field in response.<br />
Subsequently <em>&#8220;Vary: Host&#8221;</em> header from Apache will force Varnish not to cache otherwise cacheable content.</strong></p>
<blockquote><p>HTTP Vary is not a trivial concept. It is by far the most misunderstood HTTP header. (Varnish Docs)</p></blockquote>
<p>On a project I&#8217;ve been working, I could not make Varnish hard cache the site no matter what I did.<br />
It was mostly read-only site and I wanted to achieve that in case of backend failures &#8211; site would still run from the cache.  To avoid surprises, I was using my own configuration template which was working exactly as I wanted it on different project. </p>
<p>But, no matter what I did &#8211; Varnish was not caching everything. Instead I got &#8216;<em>per-user</em>&#8216; cache: if user visited eg, homepage, in case of backend failure &#8211; user could reload homepage and Varnish would serve homepage from stale cache to the user. Visiting any other page user did not visit before backend failure (and therefore not in his cache), would result in Varnish freaking that backend is down.</p>
<p>What I noticed was strangely large Vary-Header in Varnish response</p>
<pre class="brush: plain; title: ; notranslate">
Vary:Host,Accept-Encoding,User-Agent
</pre>
<p>After spending hours of tunneling, debugging Varnish configuration, analysing header responses, comparing server configurations, hunting for cookies that could have been somehow magically slip through&#8230; last place I looked was my main .htaccess. I was using mod_deflate there, but as it checked out everything was fine.</p>
<p>On a side note, I have been experimenting with per host configuration in .htaccess, so Basic Authentication would not kick in dev enviroment. It was working great up until now, and it goes something like this:</p>
<pre class="brush: plain; title: ; notranslate">
&lt;if &quot;%{HTTP_HOST} == 'dev.nivas.hr'&quot;&gt;

Require valid-user
...
Allow from facebook.com

&lt;/if&gt;
</pre>
<p>What I had to find out the hard way, is that if special Apache enviroment variable <strong>%{HTTP_HOST}</strong> was used in a eg. .htaccess, Apache would change response header. Server was returning a header which included a “<strong>Vary: Host</strong>” field, which means that the server didn’t serve a regular static page, but its reply depends on the “Host” field in the HTTP request. Browsers interpret this as “the content returned is dynamic, don’t cache it (<a href="http://blog.iosart.com/2004/05/26/fooling-apache/">source</a>).</p>
<pre class="brush: plain; title: ; notranslate">
curl -I http://localhost/
HTTP/1.1 200 OK
Date: Mon, 13 Feb 2017 14:48:14 GMT
Server: Apache/2.4.6 (CentOS)
Vary: Host,User-Agent
Content-Type: text/html; charset=UTF-8
</pre>
<p>It is really strange I did not hit this before because RewriteCond can add &#8220;Host&#8221; to the Vary-Header as well. eg. a RewriteCond that evaluates %{HTTP_HOST} automatically adds &#8220;Host&#8221; to the Vary-Header. This is unnecessary and not permitted according to <a href="https://tools.ietf.org/html/rfc7231#section-7.1.4">https://tools.ietf.org/html/rfc7231#section-7.1.4</a>. The issue was reported and has been sitting in Apache bugtraq <a href="https://bz.apache.org/bugzilla/show_bug.cgi?id=58231">for a while</a> without clear resolution.</p>
<p>I can understand why Varnish is not caching, but cannot understand Apache logic. I do have VirtualHost defined, so therefore my request do vary on Host. There is no need in forcing this out in response.  </p>
<p>After removing %{HTTP_HOST} from .htaccess, site was cacheable as we wanted.</p>
<pre class="brush: plain; title: ; notranslate">
HTTP/1.1 200 OK
Date: Mon, 13 Feb 2017 22:18:33 GMT
Content-Type: text/html; charset=UTF-8
Vary: Accept-Encoding
Age: 3707
X-Nivas-Crew: loves you :) https://www.nivas.hr
X-Backend: backend_app1
X-Cache: HIT
X-Cache-Hits: 786332
X-Vudu-Url-Cache: hit
</pre>
<p>Don&#8217;t forget to normalize your Vary in Varnish, chance are without normalization it will never see a cache hit.</p>
<p>Happy caching!</p>
<h2>
Have a cool Varnish project you need help on? <a href="https://www.nivas.hr/contact">Contact us</a>.<br />
</h2>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2017/02/13/apache-sending-vary-host-making-things-uncacheable-varnish/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Proper way to include Facebook SDK for Javascript and jQuery &#8230;</title>
		<link>https://www.nivas.hr/blog/2016/10/29/proper-way-include-facebook-sdk-javascript-jquery/</link>
					<comments>https://www.nivas.hr/blog/2016/10/29/proper-way-include-facebook-sdk-javascript-jquery/#comments</comments>
		
		<dc:creator><![CDATA[damir]]></dc:creator>
		<pubDate>Sat, 29 Oct 2016 14:14:36 +0000</pubDate>
				<category><![CDATA[developers journal]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[fb]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[race condition]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2514</guid>

					<description><![CDATA[&#8230; and avoid race condition! :) Although fb is pretty clear on how to do it (http://bit.ly/2eGfFDv) – many developers are still doing it wrong. So this blog post is here to be reminder for me and others, also it will propose small upgrade to the fb recommended practice. The naive and wrong way to...]]></description>
										<content:encoded><![CDATA[<h2>&#8230; and avoid race condition! :)</h2>
<p>Although fb is pretty clear on how to do it (<a href="http://bit.ly/2eGfFDv" target="_blank">http://bit.ly/2eGfFDv</a>)  – many developers are still doing it wrong.  So this blog post is here to be reminder for me and others, also it will propose small upgrade to the fb recommended practice.</p>
<h2>The naive and wrong way to do it</h2>
<pre class="brush: xml; title: ; notranslate">
&lt;script src=&quot;//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
window.fbAsyncInit = function()
	{
		FB.init({
			appId      : 'your-app-id',
			xfbml      : true,
			version    : 'v2.8'
			});
		
		// do something with DOM and jQuery
		$('#loginbutton,#feedbutton').removeAttr('disabled');
		FB.getLoginStatus(updateStatusCallback);
	};

  (function(d, s, id){
     var js, fjs = d.getElementsByTagName(s)[0];
     if (d.getElementById(id)) {return;}
     js = d.createElement(s); js.id = id;
     js.src = &quot;//connect.facebook.net/en_US/sdk.js&quot;;
     fjs.parentNode.insertBefore(js, fjs);
   }(document, 'script', 'facebook-jssdk'));
&lt;/script&gt;
</pre>
<p>The problem with this is the race condition: at the time fbAsyncInit gets called there is no guaranty  that  DOM is ready and that #loginbutton or #feedbutton is there, ready to be used.</p>
<p>This bug is hard to spot and debug – since it will not always manifest. It is very likely that you as developer with fast connection and computer will never  experience this bug – but your clients (visitors) might. </p>
<p><img loading="lazy" src="https://www.nivas.hr/blog/wp-content/uploads/2016/10/meme-450x338.jpg" alt="meme" width="450" height="338" class="aligncenter size-medium wp-image-2515" srcset="https://www.nivas.hr/blog/wp-content/uploads/2016/10/meme-450x338.jpg 450w, https://www.nivas.hr/blog/wp-content/uploads/2016/10/meme.jpg 604w" sizes="(max-width: 450px) 100vw, 450px" /></p>
<p>So it is best not to leave this to chance since fix is so easy.</p>
<h2>Facebook recommendation</h2>
<p>Learn more: <a href="http://bit.ly/2eGfFDv" target="_blank">http://bit.ly/2eGfFDv</a></p>
<pre class="brush: xml; title: ; notranslate">
&lt;script src=&quot;//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
$(document).ready(function()
{
	$.ajaxSetup({ cache: true });
	
	$.getScript('//connect.facebook.net/en_US/sdk.js',
				function()
				{
					FB.init({
					appId: '{your-app-id}',
					version: 'v2.8'
				}
			);

		$('#loginbutton,#feedbutton').removeAttr('disabled');
		FB.getLoginStatus(updateStatusCallback);
	});
});
&lt;/script&gt;
</pre>
<p>Problem with this approach is that you are changing global jQuery ajax cache settings.</p>
<h2>The better way</h2>
<pre class="brush: xml; title: ; notranslate">
&lt;script src=&quot;//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
$(document).ready(function()
{
	$.ajax(
			{
				url: '//connect.facebook.net/en_US/sdk.js',
				dataType: 'script',
				cache: true,
				success:function(script, textStatus, jqXHR)
				{
					FB.init(
						{
							appId      : '{your-app-id}',
							xfbml      : true,
							version    : 'v2.8'
						}
					);
					
					$('#loginbutton,#feedbutton').removeAttr('disabled');
					FB.getLoginStatus(updateStatusCallback);
				}
			});
});
&lt;/script&gt;
</pre>
<p>Now we did it. No race condition between jQuery, fb SDK for JS and loading of DOM. Also global jQuery Ajax settings are untouched. </p>
<p>Cheers! :)</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2016/10/29/proper-way-include-facebook-sdk-javascript-jquery/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>UX fail: Crazy Crazy Egg create account</title>
		<link>https://www.nivas.hr/blog/2016/10/26/ux-fail-crazy-crazy-egg-create-account/</link>
					<comments>https://www.nivas.hr/blog/2016/10/26/ux-fail-crazy-crazy-egg-create-account/#respond</comments>
		
		<dc:creator><![CDATA[damir]]></dc:creator>
		<pubDate>Wed, 26 Oct 2016 14:20:02 +0000</pubDate>
				<category><![CDATA[developers journal]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2506</guid>

					<description><![CDATA[This is Crazy Egg create account screen from my point of view: I was quite amused by the empty mysterious input field. :) But, being the web developer for a decade (at least) &#8211; I knew what needs to be done: Dear Crazy Egg users &#8211; get down on your knees and take a look...]]></description>
										<content:encoded><![CDATA[<p>This is <a href="http://www.crazyegg.com" target="_blank">Crazy Egg</a> create account screen from my point of view:</p>
<p><a href="https://www.nivas.hr/blog/wp-content/uploads/2016/10/sml_DSC_1304.jpg"><img loading="lazy" src="https://www.nivas.hr/blog/wp-content/uploads/2016/10/sml_DSC_1304-450x253.jpg" alt="sml_dsc_1304" width="450" height="253" class="aligncenter size-medium wp-image-2508" srcset="https://www.nivas.hr/blog/wp-content/uploads/2016/10/sml_DSC_1304-450x253.jpg 450w, https://www.nivas.hr/blog/wp-content/uploads/2016/10/sml_DSC_1304-768x432.jpg 768w, https://www.nivas.hr/blog/wp-content/uploads/2016/10/sml_DSC_1304-1024x576.jpg 1024w, https://www.nivas.hr/blog/wp-content/uploads/2016/10/sml_DSC_1304.jpg 1600w" sizes="(max-width: 450px) 100vw, 450px" /></a></p>
<p>I was quite amused by the empty mysterious input field. :)<br />
But, being the web developer for a decade (at least) &#8211; I knew what needs to be done:<br />
Dear Crazy Egg users &#8211; <strong>get down on your knees</strong> and take a look upwards, and voila:</p>
<p><a href="https://www.nivas.hr/blog/wp-content/uploads/2016/10/sml_DSC_1305.jpg"><img loading="lazy" src="https://www.nivas.hr/blog/wp-content/uploads/2016/10/sml_DSC_1305-450x253.jpg" alt="crazy egg, ux fail" width="450" height="253" class="size-medium wp-image-2507" srcset="https://www.nivas.hr/blog/wp-content/uploads/2016/10/sml_DSC_1305-450x253.jpg 450w, https://www.nivas.hr/blog/wp-content/uploads/2016/10/sml_DSC_1305-768x432.jpg 768w, https://www.nivas.hr/blog/wp-content/uploads/2016/10/sml_DSC_1305-1024x576.jpg 1024w, https://www.nivas.hr/blog/wp-content/uploads/2016/10/sml_DSC_1305.jpg 1600w" sizes="(max-width: 450px) 100vw, 450px" /></a></p>
<p>Mystery solved.</p>
<p>Also we tested this screen on several monitors, with slightly different points of view (we are diverse company in which developers range in height from 167 to 198cm) &#8211; in all cases content of the input field is not visible or at best barely visible. </p>
<p>So, do you want to share best UX fails you encountered? </p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2016/10/26/ux-fail-crazy-crazy-egg-create-account/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Delete node_modules dir in Windows</title>
		<link>https://www.nivas.hr/blog/2016/10/19/delete-node_modules-dir-in-windows/</link>
					<comments>https://www.nivas.hr/blog/2016/10/19/delete-node_modules-dir-in-windows/#comments</comments>
		
		<dc:creator><![CDATA[Luka U.]]></dc:creator>
		<pubDate>Wed, 19 Oct 2016 19:40:51 +0000</pubDate>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[windows]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2493</guid>

					<description><![CDATA[You are a happy Windows user. You have just upgraded your nodejs (if you can) and now you have to delete local /node_modules directory to install brand new packages. Problems? The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name...]]></description>
										<content:encoded><![CDATA[<p>You are a happy Windows user. You have just upgraded your nodejs (if you can) and now you have to delete local /node_modules directory to install brand new packages. Problems?</p>
<blockquote><p>The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters</p></blockquote>
<p>Yes, Windows can&#8217;t delete this directory because of the limitations in system. What now? Don&#8217;t worry, NPM comes to the rescue.</p>
<p>Just install Node package rimraf.</p>
<pre class="brush: bash; title: ; notranslate">
&gt; npm install rimraf -g
</pre>
<p>Move to direcotry above node_modules and execute.</p>
<pre class="brush: bash; title: ; notranslate">
&gt; rimraf node_modules
</pre>
<p><a href="https://www.nivas.hr/blog/wp-content/uploads/2016/10/4466041.jpg"><img loading="lazy" class="alignnone size-full wp-image-2499" src="https://www.nivas.hr/blog/wp-content/uploads/2016/10/4466041.jpg" alt="4466041" width="401" height="400" srcset="https://www.nivas.hr/blog/wp-content/uploads/2016/10/4466041.jpg 401w, https://www.nivas.hr/blog/wp-content/uploads/2016/10/4466041-150x150.jpg 150w" sizes="(max-width: 401px) 100vw, 401px" /></a></p>
<p>Tell me how it goes :)</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2016/10/19/delete-node_modules-dir-in-windows/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Google Chrome installer failed to start</title>
		<link>https://www.nivas.hr/blog/2014/01/23/google-chrome-installer-failed-to-start/</link>
					<comments>https://www.nivas.hr/blog/2014/01/23/google-chrome-installer-failed-to-start/#comments</comments>
		
		<dc:creator><![CDATA[seven]]></dc:creator>
		<pubDate>Thu, 23 Jan 2014 14:49:05 +0000</pubDate>
				<category><![CDATA[developers journal]]></category>
		<category><![CDATA[chrome]]></category>
		<category><![CDATA[windows]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2392</guid>

					<description><![CDATA[TL;DR Manually delete Chrome uninstaller left overs on Windows to get rid off &#8220;Google Chrome installer failed to start&#8221; error during reinstall. Some time last week Google Chrome browser on all workstations (Win7 x64) I use got their preference files corrupted and as a result I lost all my bookmarks, extensions etc. Internet paranoid as...]]></description>
										<content:encoded><![CDATA[<p>TL;DR Manually delete Chrome uninstaller left overs on Windows to get rid off &#8220;Google Chrome installer failed to start&#8221; error during reinstall.</p>
<p><img loading="lazy" src="https://www.nivas.hr/blog/wp-content/uploads/2014/01/bad-chrome-bad_250.jpg" alt="bad-chrome-bad_250" width="150" height="160" class="alignnone size-full wp-image-2399" align="right" /></p>
<p>Some time last week Google Chrome browser on all workstations (Win7 x64) I use got their preference files corrupted and as a result I lost all my bookmarks, extensions etc. </p>
<p>Internet paranoid as I am, first thing for me was to scan for viruses, and luckily did not find any (just some friendly AdWare my beloved Lenovo has preinstalled for me but that&#8217;s another post). Just in case &#8211; I uninstalled Chrome and cleaned up registry using <a href="http://www.piriform.com/ccleaner" target="_blank">ccleaner</a> before I do a clean install. One restart later, I was heading to <a href="https://www.google.com/intl/en/chrome/browser/" target="_blank">google.com</a> with my ol&#8217;trusty Internet Explorer in order to download and run Chrome installer. </p>
<p>What happened next was beyond everything I was prepared for &#8211; Google Chrome was unable to install throwing a undescriptive message: &#8220;<strong><em>Installation failed. The Google Chrome installer failed to start.</em></strong>&#8220;. Tried everything. Restarting, cleaning left over Chrome stuff manually from disk and registry, downloading and running alternate <a href="https://support.google.com/installer/answer/126299?hl=en" target="_blank">(offline) Google Chrome installer</a>. No luck. Each time this irritating graphics slammed me:<br />
<img loading="lazy" src="https://www.nivas.hr/blog/wp-content/uploads/2014/01/chrome-install-bug.png" alt="chrome-install-bug" width="535" height="136" class="alignnone size-full wp-image-2393" style='border:1px solid #000000' srcset="https://www.nivas.hr/blog/wp-content/uploads/2014/01/chrome-install-bug.png 535w, https://www.nivas.hr/blog/wp-content/uploads/2014/01/chrome-install-bug-450x114.png 450w" sizes="(max-width: 535px) 100vw, 535px" /></p>
<p>The funny lol moment was reached when I googled for manual chrome uninstall:<br />
<img loading="lazy" src="https://www.nivas.hr/blog/wp-content/uploads/2014/01/uninstall.png" alt="uninstall" width="537" height="241" class="alignnone size-full wp-image-2402" style='border:1px solid #000000' srcset="https://www.nivas.hr/blog/wp-content/uploads/2014/01/uninstall.png 537w, https://www.nivas.hr/blog/wp-content/uploads/2014/01/uninstall-450x201.png 450w" sizes="(max-width: 537px) 100vw, 537px" /></p>
<p>First result, on Google support forum <a href="https://support.google.com/chrome/answer/111899?hl=en" target="_blank">https://support.google.com/chrome/answer/111899?hl=en</a> results in a &#8211; <strong>Page not available</strong>. *FACEPALM*</p>
<p>After hours of wasting my time googling I started considering a Windows re-install.<br />
But at the end, digging through registry paid off. Found additional &#8216;special&#8217; key which nobody mentioned nowhere for x64 os (Wow6432Node). After deleting it, I was finally able to reinstall Chrome.</p>
<p>First thing I did after I reinstalled it &#8211; I run ccleaner and &#8211; corrupted Chrome settings. Luckily I could repeat uninstall/reinstall procedure knowing what I was forced to learn. :)</p>
<p>Hope it will help somebody.</p>
<p><strong>Solution</strong><br />
To fix &#8220;Chrome installer failed to start&#8221; issue, you have to manually delete Chrome uninstaller left overs:<br />
1. Delete &#8220;<strong>%APPDATA%\Google</strong>&#8221; folder and all of it&#8217;s contents<br />
2. Delete following registry keys:<br />
<strong>HKEY_LOCAL_MACHINE\SOFTWARE \Google\<br />
HKEY_CURRENT_USER\SOFTWARE \Google\</strong></p>
<p>And the most important &#8211; for 64-bit Windows, delete also<br />
<strong>HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Google\</strong></p>
<p>3. If you by any chance use ccleaner or any similar utility for deleting your browser/system cache, and you update your browsers regularly &#8211; be 100% sure to  <strong>always update</strong> the cleaning apps to newest versions to avoid corruption of your browsers configuration.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2014/01/23/google-chrome-installer-failed-to-start/feed/</wfw:commentRss>
			<slash:comments>15</slash:comments>
		
		
			</item>
		<item>
		<title>ZgPHP meetup conference 2013</title>
		<link>https://www.nivas.hr/blog/2013/09/10/zgphp-meetup-conference-2013/</link>
					<comments>https://www.nivas.hr/blog/2013/09/10/zgphp-meetup-conference-2013/#respond</comments>
		
		<dc:creator><![CDATA[seven]]></dc:creator>
		<pubDate>Tue, 10 Sep 2013 10:23:41 +0000</pubDate>
				<category><![CDATA[developers journal]]></category>
		<category><![CDATA[nivas]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2380</guid>

					<description><![CDATA[On 14th of September (this Saturday) our friends from ZgPHP user group will held a second anniversary jubilee ZgPHP Meetup and a full blown one-day PHP conference. The conference will be held in Croatian chamber of commerce offices (HGK), Nova cesta 3-7 on the second floor (entrance is located on south side of the building,...]]></description>
										<content:encoded><![CDATA[<p>On 14th of September (this Saturday) our friends from ZgPHP user group will held a second anniversary jubilee ZgPHP Meetup and a full blown one-day PHP conference. The conference will be held in Croatian chamber of commerce offices (HGK), Nova cesta 3-7 on the second floor (entrance is located on south side of the building, same entrance as Lidl). For further details check out the conference <a href="http://2013.zgphp.org/">web site</a>.</p>
<p>See you there!</p>
<p><a href="https://www.nivas.hr/blog/wp-content/uploads/2013/09/logo.png"><img loading="lazy" src="https://www.nivas.hr/blog/wp-content/uploads/2013/09/logo.png" alt="logo" width="252" height="156" class="alignnone size-full wp-image-2381" /></a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2013/09/10/zgphp-meetup-conference-2013/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Transformed elements rendering fonts poorly in chrome</title>
		<link>https://www.nivas.hr/blog/2013/02/27/transformed-elements-rendering-fonts-poorly-in-chrome/</link>
					<comments>https://www.nivas.hr/blog/2013/02/27/transformed-elements-rendering-fonts-poorly-in-chrome/#comments</comments>
		
		<dc:creator><![CDATA[Badu]]></dc:creator>
		<pubDate>Wed, 27 Feb 2013 11:24:14 +0000</pubDate>
				<category><![CDATA[css]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2362</guid>

					<description><![CDATA[For needs of our latest project we were making element that&#8217;s resembles droplet which has some text in it. So of course we would make it without images, so to make droplet we made a square with 3 corners with border radius 50%, and rotated the element for 45 degrees, and then rotated text in...]]></description>
										<content:encoded><![CDATA[<p>For needs of our latest project we were making element that&#8217;s resembles droplet which has some text in it. So of course we would make it without images, so to make droplet we made a square with 3 corners with border radius 50%, and rotated the element for 45 degrees, and then rotated text in opposite direction for again 45 degrees.</p>
<p>That works nicely, we can have box shadows, and background diagonal gradients, it looks nice, but for the problems in chrome, which renders fonts poorly? There is no one rule solution for this problem, the solution is not to rotate text element, chrome can’t handle it.</p>
<p>Workaround for this problem is to have two separate elements standing one on top of the other, so one can be rotated (gradient/droplet) and text element must not have transform rotate on it.</p>
<p><img loading="lazy" class="alignnone size-full wp-image-2364" alt="font" src="https://www.nivas.hr/blog/wp-content/uploads/2013/02/font.png" width="334" height="200" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2013/02/27/transformed-elements-rendering-fonts-poorly-in-chrome/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Trouble with z-indexing pseudo elements.</title>
		<link>https://www.nivas.hr/blog/2013/02/08/trouble-with-z-indexing-pseudo-elements/</link>
					<comments>https://www.nivas.hr/blog/2013/02/08/trouble-with-z-indexing-pseudo-elements/#comments</comments>
		
		<dc:creator><![CDATA[Badu]]></dc:creator>
		<pubDate>Fri, 08 Feb 2013 09:26:12 +0000</pubDate>
				<category><![CDATA[css]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2345</guid>

					<description><![CDATA[Pseudo elements are great little things, they can help you make nice little graphical feathers without writing extra markup, or they can provide description elements putting url(), attr(), counter() into content property. But when making flags or some similar extra graphical feathers, pseudo class element seems to have larger z-index then his parent element, which...]]></description>
										<content:encoded><![CDATA[<p>Pseudo elements are great little things, they can help you make nice little graphical feathers without writing extra markup, or they can provide description elements putting url(), attr(), counter() into content property.</p>
<p>But when making flags or some similar extra graphical feathers, pseudo class element seems to have larger z-index then his parent element, which defeats the purpose, so this is how you make it better :)</p>
<ol>
<li>Parent element must have z-index set.</li>
<li>Pseudo patent element must not have defined z-index</li>
<li>Pseudo element must have z-index set to negative value</li>
</ol>
<pre class="brush: plain; title: ; notranslate">
#parent {
    position: relative;
    width: 200px;
    height: 200px;
    z-index: 1;
    background-color: blue;
    margin-left:35%;
}

#pseudo-parent {
    position: absolute;
}

#pseudo-parent:after {
    content: &quot;&quot;;
    width: 100px;
    height: 100px;
    display: block;
    position: absolute;
    z-index: -1;
    background-color: red;
    top:0;
    left:-25px;
}
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2013/02/08/trouble-with-z-indexing-pseudo-elements/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Upgrade to Apache 2.4 and AddOutputFilterByType issue</title>
		<link>https://www.nivas.hr/blog/2012/08/10/upgrade-to-apache-2-4-and-addoutputfilterbytype-issue/</link>
					<comments>https://www.nivas.hr/blog/2012/08/10/upgrade-to-apache-2-4-and-addoutputfilterbytype-issue/#comments</comments>
		
		<dc:creator><![CDATA[seven]]></dc:creator>
		<pubDate>Fri, 10 Aug 2012 10:46:13 +0000</pubDate>
				<category><![CDATA[developers journal]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2332</guid>

					<description><![CDATA[For quite some time now, we have been using Apache module mod_deflate to gzip some static content served by Apache automatically: If you upgraded from Apache 2.2 to 2.4, you will notice error in your apache log: Invalid command &#8216;AddOutputFilterByType&#8217;, perhaps misspelled or defined by a module not included in the server configuration. To fix...]]></description>
										<content:encoded><![CDATA[<p>For quite some time now, we have been using Apache module mod_deflate to gzip some static content served by Apache automatically:</p>
<pre class="brush: plain; title: ; notranslate">
AddOutputFilterByType DEFLATE text/html text/css application/x-javascript
</pre>
<p>If you upgraded from Apache 2.2 to 2.4, you will notice error in your apache log:<br />
<strong>Invalid command &#8216;AddOutputFilterByType&#8217;, perhaps misspelled or defined by a module not included in the server configuration.</strong></p>
<p>To fix this, enable <strong>mod_filter</strong> and restart Apache. mod_filter is required in 2.4, although in 2.2 was not the case. </p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2012/08/10/upgrade-to-apache-2-4-and-addoutputfilterbytype-issue/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Beware of max_input_vars php ini configuration option</title>
		<link>https://www.nivas.hr/blog/2012/04/04/beware-of-max_input_vars-php-ini-configuration-option/</link>
					<comments>https://www.nivas.hr/blog/2012/04/04/beware-of-max_input_vars-php-ini-configuration-option/#comments</comments>
		
		<dc:creator><![CDATA[seven]]></dc:creator>
		<pubDate>Wed, 04 Apr 2012 18:02:08 +0000</pubDate>
				<category><![CDATA[developers journal]]></category>
		<category><![CDATA[nivas]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2324</guid>

					<description><![CDATA[If you are updating PHP on your production server, beware of relatively new max_input_vars php.ini directive which is now 1000 by default. That means if you have 1001 form field &#8211; only 1000 form fields will be submitted. Use of this directive mitigates the possibility of denial of service attacks which use hash collisions in...]]></description>
										<content:encoded><![CDATA[<p>If you are updating PHP on your production server, beware of relatively new <a href="http://www.php.net/manual/en/info.configuration.php#ini.max-input-vars">max_input_vars</a> php.ini directive which is now 1000 by default. That means if you have 1001 form field &#8211; only 1000 form fields will be submitted. Use of this directive mitigates the possibility of denial of service attacks which use hash collisions in connection with <a href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2011-4885">CVE-2011-4885</a>. </p>
<p>From php changelog:<br />
<code><br />
2012-01-03 : security / trunk - Added php-5.2-max-input-vars patch max_input_vars directive to prevent attacks based on hash collisions - CVE-2011-4885<br />
</code></p>
<p>Why we have so much form fields is a subject for different post. The main problem is that even php site says this update is available from PHP version 5.3.9. The fact is we have 5.3.2-1ubuntu4.14 and the update is there. </p>
<p>So&#8230; you know&#8230; beware. :)</p>
<p><a href="https://www.nivas.hr/blog/wp-content/uploads/2012/04/max_input_vars.png"><img loading="lazy" src="https://www.nivas.hr/blog/wp-content/uploads/2012/04/max_input_vars-450x89.png" alt="" title="max_input_vars" width="450" height="89" class="alignnone size-medium wp-image-2325" srcset="https://www.nivas.hr/blog/wp-content/uploads/2012/04/max_input_vars-450x89.png 450w, https://www.nivas.hr/blog/wp-content/uploads/2012/04/max_input_vars.png 979w" sizes="(max-width: 450px) 100vw, 450px" /></a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2012/04/04/beware-of-max_input_vars-php-ini-configuration-option/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Excel stopped calculating formulas &#8211; Earth coming to an end?</title>
		<link>https://www.nivas.hr/blog/2012/03/20/excel-stopped-calculating-formulas-earth-coming-to-an-end/</link>
					<comments>https://www.nivas.hr/blog/2012/03/20/excel-stopped-calculating-formulas-earth-coming-to-an-end/#respond</comments>
		
		<dc:creator><![CDATA[seven]]></dc:creator>
		<pubDate>Tue, 20 Mar 2012 15:22:38 +0000</pubDate>
				<category><![CDATA[developers journal]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2295</guid>

					<description><![CDATA[From early 60s to modern times, spreadsheet processors play important role in every man&#8217;s day life which basic functionality is taken for granted. In the accounting a &#8220;spread sheet&#8221; was and is a large sheet of paper with columns and rows that lays everything out about transactions for a business person to examine. An electronic...]]></description>
										<content:encoded><![CDATA[<p><img loading="lazy" src="https://www.nivas.hr/blog/wp-content/uploads/2012/03/bricklinfrankston.gif" alt="" title="bricklin and frankston - spreadsheet hipsters" width="200" height="203" align="right" />From early 60s to modern times, spreadsheet processors play important role in every man&#8217;s day life which basic functionality is taken for granted. </p>
<p>In the accounting a &#8220;spread sheet&#8221; was and is a large sheet of paper with columns and rows that lays everything out about transactions for a business person to examine. An electronic spreadsheet organizes information into columns and rows. The data can then be &#8220;added up&#8221; by a formula to give a total or sum. The spreadsheet program summarizes information from many sources in one place and presents the information.<br />
If you are wondering who are those two cool spreadsheet hipsters, check out A Brief History of Spreadsheets (<a href="http://dssresources.com/history/sshistory.html">here </a>and <a href="http://www.cs.umd.edu/class/spring2002/cmsc434-0101/MUIseum/applications/spreadsheethistory1.html">here</a>). Now, let&#8217;s go back to 2012. Erm 2007.</p>
<p>Did your Excel (2007) stopped auto calculating your precious formulas out of the sudden and you are in a hurry to send cost estimates to your client? Just like mine did? Yes, that can be nasty. :)</p>
<ol>
<li>Click on the <strong>Formulas </strong>ribbon tab, </li>
<li>then select <strong>Calculation Options</strong>, </li>
<li>and then check if <strong>Automatic </strong>is on.</li>
</ol>
<p>Simple eh? How did this switch off in first place? No idea. This applies to Excel 2007, dunno about 2012:<br />
<a href="https://www.nivas.hr/blog/wp-content/uploads/2012/03/excel-formule.png"><img loading="lazy" src="https://www.nivas.hr/blog/wp-content/uploads/2012/03/excel-formule-150x150.png" alt="" title="excel-formule" width="150" height="150" class="alignnone size-thumbnail wp-image-2296" /></a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2012/03/20/excel-stopped-calculating-formulas-earth-coming-to-an-end/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Alarm and Bluetooth icons in iOS</title>
		<link>https://www.nivas.hr/blog/2012/03/13/alarm-and-bluetooth-icons-in-ios/</link>
					<comments>https://www.nivas.hr/blog/2012/03/13/alarm-and-bluetooth-icons-in-ios/#comments</comments>
		
		<dc:creator><![CDATA[Daemon]]></dc:creator>
		<pubDate>Tue, 13 Mar 2012 14:31:42 +0000</pubDate>
				<category><![CDATA[developers journal]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2275</guid>

					<description><![CDATA[I was looking at the iPhone (iOS) top system bar and one thing was bothering me in particular, but I could not place my finger on it. Yesterday I figured it out. Alarm icon, and rarely, Bluetooth icon. If we segment the top bar into three pieces (left, central, right) each of which has a...]]></description>
										<content:encoded><![CDATA[<p>I was looking at the iPhone (iOS) top system bar and one thing was bothering me in particular, but I could not place my finger on it. Yesterday I figured it out. Alarm icon, and rarely, Bluetooth icon.</p>
<p><a href="https://www.nivas.hr/blog/wp-content/uploads/2012/03/alarm-iphone.png"><img loading="lazy" src="https://www.nivas.hr/blog/wp-content/uploads/2012/03/alarm-iphone.png" alt="" title="alarm-iphone" width="640" height="459" class="alignnone size-full wp-image-2280" srcset="https://www.nivas.hr/blog/wp-content/uploads/2012/03/alarm-iphone.png 640w, https://www.nivas.hr/blog/wp-content/uploads/2012/03/alarm-iphone-450x322.png 450w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>
<p>If we segment the top bar into three pieces (left, central, right) each of which has a particular info to convey, the structure is pretty clean. On the left there is info about connectivity, signal strength, wireless, 3G etc. Middle part is reserved for time, and on the right there is battery info.</p>
<p>The problem starts when additional icons show up, in particular Alarm and Bluetooth. The Bluetooth icon is an obvious candidate to be moved on the left side since all the connectivity is there. There is no reason to dislocate Bluetooth to the right.</p>
<p>Alarm icon has two problems.</p>
<p>First, an icon itself. Clock. Clock is a wrong communication on many levels. I can clearly remember few years ago when I first got iPhone that this icon meant nothing to me.  I set the Alarm and had no idea a Clock icon means that I have an alarm setup. Throughout user interfaces of the world alarm was mostly represented by a ringing bell. This not only is a better visual communication but also is a logical translation of the ancient real-life alarms (church bells) into digital era.</p>
<p>Second problem is the position. When a clock icon appears next to battery icon, what does that mean? It means nothing, exactly. Alarm icon must be placed next to time, because they are both time related bits of information.</p>
<p><strong>Additional Hate</strong><br />
While doing this I found out this little bit of not-so-perfect design. Three icons, each of them has different shade of grayish color. How did Steve miss that one out? Also, minute-hand is not centered. My OCD is kicking in now, I have to stop dissecting these icons.</p>
<p><a href="https://www.nivas.hr/blog/wp-content/uploads/2012/03/3-ikone1.png"><img loading="lazy" src="https://www.nivas.hr/blog/wp-content/uploads/2012/03/3-ikone1.png" alt="" title="3-ikone" width="640" height="242" class="alignnone size-full wp-image-2283" srcset="https://www.nivas.hr/blog/wp-content/uploads/2012/03/3-ikone1.png 640w, https://www.nivas.hr/blog/wp-content/uploads/2012/03/3-ikone1-450x170.png 450w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2012/03/13/alarm-and-bluetooth-icons-in-ios/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Non-breaking white space Internet Explorer 8 JavaScript regexp bug (and how to fix it)</title>
		<link>https://www.nivas.hr/blog/2012/01/19/non-breaking-white-space-in-internet-explorer-8-bug-and-how-to-fix-it/</link>
					<comments>https://www.nivas.hr/blog/2012/01/19/non-breaking-white-space-in-internet-explorer-8-bug-and-how-to-fix-it/#comments</comments>
		
		<dc:creator><![CDATA[damir]]></dc:creator>
		<pubDate>Thu, 19 Jan 2012 10:48:25 +0000</pubDate>
				<category><![CDATA[developers journal]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2218</guid>

					<description><![CDATA[While developing jQuery plugin for upcoming bookmarking &#8220;Items in select boxes&#8221; plugin for our Vudu CMS I wrote a simple regexp to strip few characters (pipe, minus, apostrof and white-space) that are added before the actual item. It worked just fine on FF9 and Chrome but in IE8 only the first pipe (&#124;) was removed....]]></description>
										<content:encoded><![CDATA[<p>While developing jQuery plugin for upcoming bookmarking &#8220;Items in select boxes&#8221; plugin for our <a href="https://www.nivas.hr/en/vudu-cms" target="_blank">Vudu CMS</a></p>
<p><img loading="lazy" class="aligncenter size-full wp-image-2232" title="img1" src="https://www.nivas.hr/blog/wp-content/uploads/2012/01/img1.jpg" alt="" width="400" height="60" /></p>
<p>I wrote a simple regexp to strip few characters (pipe, minus, apostrof and white-space) that are added before the actual item.</p>
<pre class="brush: jscript; title: ; notranslate">
 function cleanOptionText(txt)
 {
 return txt.replace(/^[\s|'-]+/, '');
 };
</pre>
<p>It worked just fine on FF9 and Chrome but in IE8 only the first pipe (|) was removed. After some debugging I discovered that I have both spaces and non-breaking spaces that should be removed and that in IE8 class shorthand <code>\s</code> (which should include all white space) doesn’t include non-breaking space.</p>
<p>Code for non-breaking space is 0xa0 (dec 160) so regexp should be updated as follows:</p>
<pre class="brush: jscript; title: ; notranslate">
function cleanOptionText(txt)
{
return txt.replace(/^[\s\xA0|'-]+/, '');
};
</pre>
<p><span id="more-2218"></span></p>
<p>Also we took opportunity to update our javascript trim functions:</p>
<pre class="brush: jscript; title: ; notranslate">
String.prototype.trim = function()
{
return this.replace(/^[\s\xA0]+|[\s\xA0]+$/g,&quot;&quot;);
}

String.prototype.ltrim = function()
{
return this.replace(/^[\s\xA0]+/g,&quot;&quot;);
}

String.prototype.rtrim = function()
{
return this.replace(/[\s\xA0]+$/g,&quot;&quot;);
}
</pre>
<p>Here is complete html test file:</p>
<pre class="brush: xml; title: ; notranslate">

&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
  &lt;head&gt;
    &lt;title&gt;nbsp test&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;form action=&quot;#&quot;&gt;
      &lt;fieldset&gt;
      &lt;select id=&quot;testselect&quot;&gt;
        &lt;option value=&quot;1&quot;&gt;&amp;nbsp; &amp;nbsp; Some option&lt;/option&gt;
      &lt;/select&gt;
      &lt;/fieldset&gt;
    &lt;/form&gt;

    &lt;script type=&quot;text/javascript&quot;&gt;
      /*&lt;![CDATA[*/

      var txt=document.getElementById('testselect').options[0].text;

      var analyizeTxt='';
      var l=txt.length;
      for(var i=0; i&lt;l; i++)
      {
        analyizeTxt+= '[ ('+txt.charCodeAt(i)+')=('+txt.charAt(i)+')]';
      }

      alert(analyizeTxt);

      var newTxt1 = txt.replace(/^\s+/, '');
      alert('Using only \\s = ('+newTxt1+')');


      var newTxt2 = txt.replace(/^[\s\xA0]+/, '');
      alert('Using \\s and \\xA0= ('+newTxt2+')');
      /*]]&gt;*/
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;

</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2012/01/19/non-breaking-white-space-in-internet-explorer-8-bug-and-how-to-fix-it/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Ubuntu Cloud Live on OpenStack</title>
		<link>https://www.nivas.hr/blog/2012/01/19/ubuntu-cloud-live-on-openstack/</link>
					<comments>https://www.nivas.hr/blog/2012/01/19/ubuntu-cloud-live-on-openstack/#respond</comments>
		
		<dc:creator><![CDATA[seven]]></dc:creator>
		<pubDate>Thu, 19 Jan 2012 09:12:00 +0000</pubDate>
				<category><![CDATA[developers journal]]></category>
		<guid isPermaLink="false">https://www.nivas.hr/blog/?p=2207</guid>

					<description><![CDATA[crm.com published selection of the 10 Best Open-Source Products Of 2011. On 8th place, you can find OpenStack (an open-source cloud platform) for whom our dear coleague Ante Karamatić is leading Ubuntu Cloud Live project. We are looking forward to new interesting grounds cloud support will bring us in 2012. Ante explained: &#8220;Ubuntu Cloud is...]]></description>
										<content:encoded><![CDATA[<p>crm.com published selection of the <a href="http://www.crn.com/slide-shows/applications-os/232300382/the-10-best-open-source-products-of-2011.htm?pgno=4">10 Best Open-Source Products Of 2011</a>. On 8th place, you can find <a href="http://openstack.org/projects/">OpenStack</a> (an open-source cloud platform) for whom our dear coleague Ante Karamatić is leading <a href="https://launchpad.net/cloud-live">Ubuntu Cloud Live</a> project. We are looking forward to new interesting grounds cloud support will bring us in 2012.</p>
<p>Ante explained: &#8220;Ubuntu Cloud is a product. Ubuntu Live Cloud is a custom version of Ubuntu Cloud, customized to work without a disk. OpenStack is a major, if not essential, part of the Ubuntu Cloud.&#8221;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.nivas.hr/blog/2012/01/19/ubuntu-cloud-live-on-openstack/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
