<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7008386140022030691</id><updated>2024-10-05T06:44:41.579+03:00</updated><category term="javascript"/><category term="leadership"/><category term="tools"/><category term="development"/><category term="misc"/><category term="web stack"/><category term="css"/><category term="management"/><category term="reading digest"/><category term="communication"/><category term="crossrider"/><category term="design"/><category term="extension"/><category term="html"/><category term="drupal"/><category term="links"/><category term="micro-solution"/><category term="motivation"/><category term="php"/><category term="testing"/><category term="ui"/><category term="user experience"/><category term="wordpress"/><category term="amcharts"/><category term="blogger"/><category term="conditional link"/><category term="drupal api"/><category term="jasmine"/><category term="livestreet"/><category term="logo"/><category term="math"/><category term="mobile"/><category term="nodejs"/><category term="planning"/><category term="qunit"/><category term="read more"/><category term="svg"/><category term="views"/><title type='text'>Anton</title><subtitle type='html'>Love coding and will share interesting findings from my experience.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.amaslo.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>53</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-4730570053605942660</id><published>2016-09-26T20:28:00.002+03:00</published><updated>2016-09-26T20:28:29.378+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="crossrider"/><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="extension"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><title type='text'>Crossrider Extensions shutting down</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgA0RE5efmiTUuoLdJNhbHWDhXaISf_y_zSjDqru9DdB1ah2tyNMy_BJHZgjZ12qnv08xFRpYpsbES3SjHz3Bl_jo9FgCsTxKaDnrM9m2bHPuER93ivu7P4Li0Qa9rkikmUZWz6WQF35w/s1600/sunset-goodbye.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgA0RE5efmiTUuoLdJNhbHWDhXaISf_y_zSjDqru9DdB1ah2tyNMy_BJHZgjZ12qnv08xFRpYpsbES3SjHz3Bl_jo9FgCsTxKaDnrM9m2bHPuER93ivu7P4Li0Qa9rkikmUZWz6WQF35w/s1600/sunset-goodbye.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Right, as we&amp;nbsp;&lt;a href=&quot;http://www.amaslo.com/2016/01/crossrider-not-recommended-for-cross-browser-extensions.html&quot;&gt;observed back in January&lt;/a&gt;, Crossrider has moved away from its extensions platform, and now (the 26th of September, 2016) I received the following termination notice from them:&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;blockquote&gt;
Dear Partners,&amp;nbsp;&lt;/blockquote&gt;
&lt;blockquote&gt;
All good things must come to an end eventually and, regretfully, so does the Crossrider Extensions Development Platform.

After several years of collaborating with you, we have decided to terminate the service.&amp;nbsp;&lt;/blockquote&gt;
&lt;blockquote&gt;
Please be advised that termination of the service is effective immediately upon publication or otherwise receipt of this notice. 

For your ease, Crossrider Extensions Development Platform will remain available for another 30 days from 27.09.2016 for you to download your project code / source code / extensions, following which your data will be lost.&amp;nbsp;&lt;/blockquote&gt;
&lt;blockquote&gt;
See below an instruction note on how to download the project code from our server for your easy reference; but kindly note that Crossrider is not able to provide further assistance.

We would like to thank you for all your support and trust throughout the years and hope we can have the opportunity to collaborate again in the future.

 

Best,

Crossrider Team
&lt;/blockquote&gt;
So you can still download your source code in the remaining 30 days, and with careful review you can try to adapt it to creating your own native extensions for your preferred browsers.&lt;br /&gt;
&lt;br /&gt;
I had good results moving to WebExtensions for Firefox and Chrome, some concepts are different from Crossrider&#39;s API, but still recognizable. I have no recent experience with Safari or Edge, so can&#39;t recommend much. Feel free to add your comments.&lt;br /&gt;
&lt;br /&gt;
I&#39;ll say it again — I really enjoyed working with Safari&#39;s support team, so I wish those guys all the best, they&#39;ll do well in any company. It was a good time working with Crossrider, but I am glad that the browsers are getting their stuff together in offering easier development routes.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/4730570053605942660/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2016/09/crossrider-extensions-shutting-down.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/4730570053605942660'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/4730570053605942660'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2016/09/crossrider-extensions-shutting-down.html' title='Crossrider Extensions shutting down'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgA0RE5efmiTUuoLdJNhbHWDhXaISf_y_zSjDqru9DdB1ah2tyNMy_BJHZgjZ12qnv08xFRpYpsbES3SjHz3Bl_jo9FgCsTxKaDnrM9m2bHPuER93ivu7P4Li0Qa9rkikmUZWz6WQF35w/s72-c/sunset-goodbye.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-1412188097156734652</id><published>2016-01-21T22:54:00.000+02:00</published><updated>2016-01-21T22:54:36.023+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="html"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="math"/><category scheme="http://www.blogger.com/atom/ns#" term="motivation"/><category scheme="http://www.blogger.com/atom/ns#" term="reading digest"/><title type='text'>Reading Digest 06, or What does Leo Tolstoy have to do with it?</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWcZGYjiIR4TST7Qplh7RoIKEPnYRF1MgV5ADxRi9cUy4jCD45aC-h4eFhaJZSICIXT1hScTzquARgzS_Iv1pd3A0i1ZHIN9sMLYFjaM273Rmn1CNF93tLym-0zhOasiGxD0xZ64nIhg/s1600/tolstoy.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWcZGYjiIR4TST7Qplh7RoIKEPnYRF1MgV5ADxRi9cUy4jCD45aC-h4eFhaJZSICIXT1hScTzquARgzS_Iv1pd3A0i1ZHIN9sMLYFjaM273Rmn1CNF93tLym-0zhOasiGxD0xZ64nIhg/s1600/tolstoy.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Hello there, it&#39;s been a while, here&#39;s what interested me recently. Learning is fun!… and it will be even more fun to revisit these, say, a year from now and verify that I don&#39;t remember a thing :)&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://danthedev.com/2015/07/25/binary-in-javascript/&quot;&gt;Binary in Javascript&lt;/a&gt;—for me this firmly falls into the category “I doubt I&#39;ll ever need to use it, yet it is still very cool”. Using bitwise operators in JavaScript to pack large collections of small data.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://alistapart.com/column/write-what-you-know-now&quot;&gt;Write What You Know (Now)&lt;/a&gt;—resonates well with my reasons for writing to this blog (as rare as it happens), to leave breadcrumbs of my own experience, and also to possibly help others walking on a similar path:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;…“But nobody will read it,” you say. That may be true. But the opposite could also happen.&lt;/i&gt;&lt;/blockquote&gt;
&lt;a href=&quot;https://medium.com/content-uneditable/contenteditable-the-good-the-bad-and-the-ugly-261a38555e9c#&quot;&gt;ContentEditable — The Good, the Bad and the Ugly&lt;/a&gt;—alright, how did I missed this? There is a browser-supported (with LOTS of small print, but hey) method for inline editing of HTML contents. Looks like it existed for years, and slowly improving. Something to keep an eye on.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://betterexplained.com/articles/an-intuitive-guide-to-exponential-functions-e/&quot;&gt;An Intuitive Guide To Exponential Functions &amp;amp; e&lt;/a&gt;—as a math-head, I blush to admit my ignorance about &lt;i&gt;e&lt;/i&gt;. I knew it pops up in formulas often, and it&#39;s value is “2.7 then Leo Tolstoy&#39;s birth year twice” (I kid you not, 2.718281828…). Incidentally, that&#39;s the sole reason I know Mr.Tolstoy&#39;s year of birth. This article explains the meaning of &lt;i&gt;e&lt;/i&gt;, and even calculates its value for us. Enlightening!&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://jamesclear.com/stay-focused&quot;&gt;How to Stay Focused When You Get Bored Working Toward Your Goals&lt;/a&gt;—here&#39;s one to motivate all of us normal people who sometimes get bored, but still understand that any worthwhile goal takes some of that “while” to get some of that “worth”:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;…He was saying that really successful people feel the same boredom and the same lack of motivation that everyone else feels. They don’t have some magic pill that makes them feel ready and inspired every day. But the difference is that the people who stick with their goals don’t let their emotions determine their actions. Top performers still find a way to show up, to work through the boredom, and to embrace the daily practice that is required to achieve their goals.&lt;/i&gt;&lt;/blockquote&gt;
&lt;a href=&quot;http://www.failbettergames.com/five-things-ive-learned-at-failbetter-producer-lottie-bevan/&quot;&gt;Five things I’ve learned at Failbetter: Producer Lottie Bevan&lt;/a&gt;—good brief humane insights, where I especially second things 4 (People &amp;gt; processes) and 5&amp;nbsp;(sometimes it is OK not to plan &lt;i&gt;your&lt;/i&gt; future). Of course I&#39;d agree with a fellow&amp;nbsp;&lt;i&gt;intellectual omnivore&lt;/i&gt; (what a term!).&lt;br /&gt;
&lt;br /&gt;
Speaking of terms,&amp;nbsp;&lt;a href=&quot;https://css-tricks.com/what-is-bikeshedding/&quot;&gt;Bikeshedding&lt;/a&gt;!&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
“&lt;i&gt;…A committee whose job is to approve plans for a nuclear power plant may spend the majority of its time on relatively unimportant but easy-to-grasp issues, such as what materials to use for the staff bikeshed, while neglecting the design of the power plant itself, which is far more important but also far more difficult to criticize constructively.&lt;/i&gt;”&lt;/blockquote&gt;
Been there, done that.</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/1412188097156734652/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2016/01/reading-digest-06-or-what-does-leo-tolstoy-have-to-do-with-it.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/1412188097156734652'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/1412188097156734652'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2016/01/reading-digest-06-or-what-does-leo-tolstoy-have-to-do-with-it.html' title='Reading Digest 06, or What does Leo Tolstoy have to do with it?'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWcZGYjiIR4TST7Qplh7RoIKEPnYRF1MgV5ADxRi9cUy4jCD45aC-h4eFhaJZSICIXT1hScTzquARgzS_Iv1pd3A0i1ZHIN9sMLYFjaM273Rmn1CNF93tLym-0zhOasiGxD0xZ64nIhg/s72-c/tolstoy.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-6000017119804180531</id><published>2016-01-12T21:21:00.000+02:00</published><updated>2016-09-26T20:32:18.907+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="crossrider"/><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="extension"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="web stack"/><title type='text'>Crossrider no longer recommended for cross-browser extensions, sadly</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBNEcL_OUO1cGqgpG_9NQXkXkUALA1_hhJqY6vUQlr7vz9IJsUZL_7S5smUB-eP7-9Oy7QO2eOCzPd1eqgbmd2ELdRnqCcR1MPUO-GPGA2Sy8yg64wLaLmRYACI7PFBjbk4FpsiDDewg/s1600/broken-pier.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBNEcL_OUO1cGqgpG_9NQXkXkUALA1_hhJqY6vUQlr7vz9IJsUZL_7S5smUB-eP7-9Oy7QO2eOCzPd1eqgbmd2ELdRnqCcR1MPUO-GPGA2Sy8yg64wLaLmRYACI7PFBjbk4FpsiDDewg/s1600/broken-pier.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;b&gt;Update (2016-09-26):&lt;/b&gt; 8 months later the &lt;a href=&quot;http://www.amaslo.com/2016/09/crossrider-extensions-shutting-down.html&quot;&gt;Crossrider Extension Platform is shutting down&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Some time ago, I shared about &lt;a href=&quot;http://www.amaslo.com/2015/03/developing-javascript-browser-extensions-with-crossrider.html&quot;&gt;developing cross-browser extensions using JavaScript with Crossrider framework&lt;/a&gt;, and even investigated &lt;a href=&quot;http://www.amaslo.com/2015/04/javascript-unit-testing-in-crossrider.html&quot;&gt;unit testing these extensions&lt;/a&gt;. These articles are quite popular, so I ought to provide an update on where Crossrider stands.&lt;br /&gt;
&lt;br /&gt;
It isn&#39;t doing very well, unfortunately.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
I still think it is a solid framework with rich API. It is clear the team spent countless hours ironing out the quirks of every supported browser, and presented us with a unified development environment. I still applaud Crossrider&#39;s support team for their responsiveness and helpfulness. Thing is… browsers change, while Crossrider fails to keep up.&lt;br /&gt;
&lt;br /&gt;
Even when I started studying the framework almost two years ago, it seemed to be in a “feature complete” state, with most visible work done by the support team. There was no clear roadmap for future enhancements.&lt;br /&gt;
&lt;br /&gt;
Not much have changed. My best guess is that their development team was dramatically reduced, rerouted to another project, or both. Probably a project with more clear and direct financial gain—selling advertisements for extensions is unlikely to fly unless you work very closely with extension developers, to ensure you have lots of popular and successful extensions to sell ads for. I can&#39;t blame them—keeping a good development team afloat (looking at their framework I can say that they are a good team) takes a steady income.&lt;br /&gt;
&lt;br /&gt;
Enough of speculation. Here&#39;s what I&#39;ve seen happen with different browsers in regards to Crossrider.&lt;br /&gt;
&lt;h3&gt;
Firefox&lt;/h3&gt;
Last March I wrote:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
…One significant weakness is that currently it isn&#39;t possible to publish Crossrider extensions to Mozilla Addon Directory. which is a huge shame. Extensions fail automatic checks performed on submission, and, having gone through this process myself, I see that the complaints aren&#39;t about my code — they are about the code provided as part of Crossrider framework, and thus out of our control. Crossrider team is aware of this, yet it is hard to say whether any progress is being worked on in this regard.&lt;/blockquote&gt;
No progress here. AMO (&lt;a href=&quot;http://addons.mozilla.org/&quot;&gt;addons.mozilla.org&lt;/a&gt;) still does not allow uploading Crossrider extensions. I gather from several support threads that Mozilla&#39;s validation algorithms take issue with the way Crossrider wrapper is built. Changing it would require full rework, so they tried to “talk” to Mozilla, probably failing to impress them. Too bad.&lt;br /&gt;
&lt;br /&gt;
That&#39;s not all, though.&lt;br /&gt;
&lt;br /&gt;
In order to increase addon security for end users, Mozilla is introducing a signing process. In Firefox vv.42 and 43 it was just a warning, while v.44, slated for January 26th, 2016, will simply disallow all unsigned extensions. This may be somewhat postponed, yet looks inevitable.&lt;br /&gt;
&lt;br /&gt;
Crossrider extensions fail the signing process, even if you&amp;nbsp;&lt;a href=&quot;https://blog.mozilla.org/addons/2015/12/01/de-coupling-reviews-from-signing-unlisted-add-ons/&quot;&gt;sign it as an “unlisted” addon&lt;/a&gt;, which skips most checks required for AMO. You can check the&amp;nbsp;&lt;a href=&quot;https://getsatisfaction.com/crossrider/topics/export_to_ff_amo_problem&quot;&gt;relevant support thread&lt;/a&gt;. Response from the team is that they cannot do anything about it. Sigh.&lt;br /&gt;
&lt;br /&gt;
Thus for Firefox I recommend writing a native extension instead of using Crossrider.&lt;br /&gt;
&lt;br /&gt;
This is especially valid now that Mozilla started active implementation of&amp;nbsp;&lt;a href=&quot;https://wiki.mozilla.org/WebExtensions&quot;&gt;WebExtensions API&lt;/a&gt;, which is planned to be compatible with Chrome&#39;s extension API. It is &lt;a href=&quot;http://www.arewewebextensionsyet.com/&quot;&gt;not fully implemented yet&lt;/a&gt;, but working with Firefox Developer Edition / Nightly versions I can confirm that it has enough features in place to allow migrating from Crossrider, at least for our extension.&lt;br /&gt;
&lt;br /&gt;
WebExtension support is planned for Firefox 45, expected around end of March 2016. Great news if you&#39;d like to start developing Firefox extensions—your code will also work on Chrome (with minor tweaks)&lt;br /&gt;
&lt;br /&gt;
Of course, Mozilla also announced plans to phase out their old extension API, which caused much weeping and gnashing of teeth in the community. Let&#39;s hope this doesn&#39;t trigger such a decline in the browser&#39;s popularity that a year from now Firefox won&#39;t matter anymore, WebExtensions or not.&lt;br /&gt;
&lt;br /&gt;
It is a nice browser, especially from development point of view—still the best to develop, test and debug extensions on and for.&lt;br /&gt;
&lt;h3&gt;
Chrome&lt;/h3&gt;
Not all is well in the state of Google, either. For Crossrider, that is.&lt;br /&gt;
&lt;br /&gt;
It isn&#39;t bad yet, the extensions are fully supported and work well, but Google constantly “enhances” extension security and validation, so at one point last autumn their new algorithm axed all of Crossrider extensions.&lt;br /&gt;
&lt;br /&gt;
Ouch. You can almost hear the &lt;a href=&quot;https://getsatisfaction.com/crossrider/topics/pulled-from-chrome-webstore&quot;&gt;cries for mercy&lt;/a&gt;&amp;nbsp;in the support thread.&lt;br /&gt;
&lt;br /&gt;
Luckily, contacting Google support actually helped (I was amazed), they reinstated the extensions. Yet this is a sign that something in the Crossrider wrapper doesn&#39;t sit well with Google&#39;s logic either. It wouldn&#39;t worry me if the Crossrider development team was actively (and visibly) doing something about it, but, as it stands, the situation can only get worse as Chrome moves on and Crossrider doesn&#39;t.&lt;br /&gt;
&lt;br /&gt;
I admit, I am pessimistic here. One [solved] problem is not the end of the world. But I am pessimistic in a practical way, since we have a solution. If you use&amp;nbsp;&lt;a href=&quot;https://developer.chrome.com/extensions&quot;&gt;WebExtensions API&lt;/a&gt;&amp;nbsp;(Chrome&#39;s link this time), then you can support two browsers—Chrome and Firefox,—all with one codebase.&lt;br /&gt;
&lt;br /&gt;
So for Chrome, while there isn&#39;t much urgency, I recommend to plan your migration to native API, while keeping one eye on Mozilla&#39;s progress.&lt;br /&gt;
&lt;h3&gt;
Safari&lt;/h3&gt;
This browser is… limited. Looks like the only reason people use it is because “it came with the OS” (much like IE). It is not a healthy situation for any software, and it shows. I can only imagine the lengths the Crossrider development team went to support it, with some of framework&#39;s features still marked as “absent on Safari”.&lt;br /&gt;
&lt;br /&gt;
Yet, surprisingly, Apple&#39;s browser still lives most peacefully with Crossrider-based extensions. Perhaps this is the blessing of stagnation—it doesn&#39;t change much (even with &lt;a href=&quot;https://getsatisfaction.com/crossrider/topics/the-new-safari-extensions-gallery-from-os-x-el-capitan&quot;&gt;new extension requirements that came with El Capitan&lt;/a&gt;), so Crossrider continues to work with it like nothing ever happened.&lt;br /&gt;
&lt;br /&gt;
You need to be aware of possible &lt;a href=&quot;https://getsatisfaction.com/crossrider/topics/publishing_a_safari_extension_in_the_apple_extension_directory&quot;&gt;issues with publishing to the Apple Extension Directory&lt;/a&gt;, yet those are usually solved fairly quickly with aid of Crossrider support team.&lt;br /&gt;
&lt;br /&gt;
So, hey, Crossider is still good for Safari!… I wonder if anyone cares, though.&lt;br /&gt;
&lt;h3&gt;
Internet Explorer&lt;/h3&gt;
Quote from last March:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Theoretically, the extension should work, and for simpler extensions it should be OK to test and claim IE support. In our case, though, it is an uphill battle to try to make it work. Since so few people use it, we decided to leave working out the “IE wrinkles” as lower priority, and then it turned out that the Internet Explorer extension runs in some limited JS context, that even some simplest JavaScript functions fail to run (e.g. .indexOf, .forEach etc). The error reporting is almost absent, too, so even debugging these issues means placing tons of console.log statements around the code, trying to guess where it fails now. On top of this, updating an extension once you change something in the code doesn&#39;t always work, sometimes requiring going to Control Panel / Add &amp;amp; Remove Programs, and even that is flaky.&lt;/blockquote&gt;
And that&#39;s all I can say. We simply didn&#39;t claim IE support after those initial tests, as it would be lots of pain for our customers and for our support, so I can&#39;t tell you one way or the other: whether the situation has improved or (gasp!) got worse.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://getsatisfaction.com/crossrider/topics/ie-and-windows-10&quot;&gt;Edge is not supported&lt;/a&gt;, and no current plans to implement it. Not surprised.&lt;br /&gt;
&lt;h3&gt;
Conclusion&lt;/h3&gt;
Software development is like that. We produce perishable high-maintenance goods.&lt;br /&gt;
&lt;br /&gt;
That cute Tetris clone you wrote in Turbo Pascal 6.0 for Windows 3.11? If you didn&#39;t stay on top of things, it probably won&#39;t run easily today. The site you wrote in Notepad in 1995, making your first steps in HTML? Likely beyond repair, with GeoCities dead, domain name unpaid for decades, and even if it worked—it would look bad on today&#39;s browsers, since &amp;lt;blink&amp;gt; is no longer supported.&lt;br /&gt;
&lt;br /&gt;
Crossrider is a nice framework, and a pleasant team to interact with, so I am thankful for all their help. They saved me&amp;nbsp;tens and hundreds of hours&amp;nbsp;to support three browsers. If they manage a comeback—I&#39;ll be happy for them! Yet currently, for technical, financial, political or personal reasons, the framework is gradually sliding into history, and it is time to start looking for alternative solutions, so that we can keep our tasks—done, customers—happy, and children—fed.&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/6000017119804180531/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2016/01/crossrider-not-recommended-for-cross-browser-extensions.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/6000017119804180531'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/6000017119804180531'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2016/01/crossrider-not-recommended-for-cross-browser-extensions.html' title='Crossrider no longer recommended for cross-browser extensions, sadly'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBNEcL_OUO1cGqgpG_9NQXkXkUALA1_hhJqY6vUQlr7vz9IJsUZL_7S5smUB-eP7-9Oy7QO2eOCzPd1eqgbmd2ELdRnqCcR1MPUO-GPGA2Sy8yg64wLaLmRYACI7PFBjbk4FpsiDDewg/s72-c/broken-pier.jpg" height="72" width="72"/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-4358495735026636487</id><published>2016-01-04T18:59:00.000+02:00</published><updated>2016-01-04T18:59:42.032+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="nodejs"/><category scheme="http://www.blogger.com/atom/ns#" term="tools"/><title type='text'>A simple Telegram bot with Node.js</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8y0MJ8B0xKiW5FLg61DCyE-aX8s-uJ4T-K1S2FjfnqtTqjorLCJnikidqmvo4vILeUmLVqKgdTJdfEeweAtJsSD4o_ExcKQ-V7VzPok3KR7zfUkUga62wo1LRVC_Y6gbYmQ9AYEvAEg/s1600/telegram-bot.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8y0MJ8B0xKiW5FLg61DCyE-aX8s-uJ4T-K1S2FjfnqtTqjorLCJnikidqmvo4vILeUmLVqKgdTJdfEeweAtJsSD4o_ExcKQ-V7VzPok3KR7zfUkUga62wo1LRVC_Y6gbYmQ9AYEvAEg/s1600/telegram-bot.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Recently I found a&amp;nbsp;simple&amp;nbsp;real-life task to allow me to experiment with&amp;nbsp;&lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js&lt;/a&gt;&amp;nbsp;(I&#39;ve been peering at it and the surrounding&amp;nbsp;full-stack&amp;nbsp;JavaScript tools). Basically, I wrote a Telegram bot, which periodically posts links to Instagram photos with a specific hashtag.&lt;br /&gt;
&lt;br /&gt;
This was a learning experience for me, so a) I can&#39;t claim this is the best approach, and b) I&#39;d appreciate constructive feedback.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;h3&gt;
&lt;b&gt;The problem&lt;/b&gt;&lt;/h3&gt;
My friends from &lt;a href=&quot;http://aomegaonline.org/&quot;&gt;“Alpha and Omega” Christian Youth Centre&lt;/a&gt;&amp;nbsp;started using &lt;a href=&quot;https://telegram.org/&quot;&gt;Telegram&lt;/a&gt; messenger (it is nice, by the way, as messengers go, clean and tidy) for their conversations. Also, there is a hashtag in Instagram (&lt;a href=&quot;https://www.instagram.com/explore/tags/AlphaTopic/&quot;&gt;#AlphaTopic&lt;/a&gt;) which is used by the same group of people for weekly picture contests.&lt;br /&gt;
&lt;br /&gt;
So, a friend suggested (oh well, not my idea), that, since Telegram boasts a simple Bot API, we could implement a mechanism to post hash-tagged Instagram photos into the Telegram chat. This would increase visibility of the ongoing contests, plus could serve as a conversation starter on quieter days.&lt;br /&gt;
&lt;br /&gt;
Challenge accepted!&lt;br /&gt;
&lt;h3&gt;
Solution approach&lt;/h3&gt;
A telegram bot is a bit of server-side code, which I need to host myself, and which communicates with the API (Application Programming Interface) via simple HTTP calls. In order to be active in a given chat, it needs to be added manually by chat&#39;s patrons. Then the bot can respond to commands directed at it (if you implement this functionality) and post messages.&lt;br /&gt;
&lt;br /&gt;
There are two ways to trigger a Telegram bot, as you can check in the&amp;nbsp;&lt;a href=&quot;https://core.telegram.org/bots&quot;&gt;Telegrams Bot API&lt;/a&gt;&amp;nbsp;docs.&lt;br /&gt;
&lt;br /&gt;
One is via &lt;a href=&quot;https://core.telegram.org/bots/api#setwebhook&quot;&gt;webhooks&lt;/a&gt;. These are URLs on the bot&#39;s side, which Telegram will call once the bot receives a command from the chat where it is registered. Not a suitable method for me, since I want the bot to periodically post Instagram images, regardless of whether it was asked directly or not.&lt;br /&gt;
&lt;br /&gt;
The second method is for the bot to run by itself, for example on a Cron task, and perform whatever actions it needs. There is a complication that we need to know which chats the bot is registered in, this can be achieved by asking Telegram API whether there are any updates in the chats that it is added to, via a &lt;a href=&quot;https://core.telegram.org/bots/api#getupdates&quot;&gt;getUpdates&lt;/a&gt; call. This returns a list of recently active chats, and then you can post whatever you need to them.&lt;br /&gt;
&lt;br /&gt;
Then it is just a matter of coding a request to Instagram to get media by a hashtag, check which ones haven&#39;t been posted yet, and post them to the chat. Easy.&lt;br /&gt;
&lt;h3&gt;
Tools&lt;/h3&gt;
I tried to use free tools and services, and generally minimize bot&#39;s footprint.&lt;br /&gt;
&lt;br /&gt;
For hosting I chose &lt;a href=&quot;https://www.heroku.com/&quot;&gt;&lt;b&gt;Heroku&lt;/b&gt;&lt;/a&gt;: it supports Node.js (and lots of other addons, if needed later), and allows running a simple free web-server if it is active less than 6 hours per day. This is another reason I don&#39;t want my bot to be triggered by someone&#39;s commands—it runs when it needs to, and sleeps otherwise.&lt;br /&gt;
&lt;br /&gt;
Heroku has several Cron addons, yet I don&#39;t want to overload it for now, so employed a separate free service, &lt;a href=&quot;https://www.setcronjob.com/&quot;&gt;&lt;b&gt;SetCronJob&lt;/b&gt;&lt;/a&gt;, which allows 50 executions per day. Way more than enough, and for several months it has served me reliably.&lt;br /&gt;
&lt;br /&gt;
On &lt;b&gt;Node.js&lt;/b&gt; side I only use built-in modules: &lt;b&gt;HTTPS&lt;/b&gt; for communication, &lt;b&gt;QueryString&lt;/b&gt; to deal with POST parameters, and &lt;b&gt;Process&lt;/b&gt; to get environment variables for server-specific configuration.&lt;br /&gt;
&lt;br /&gt;
It turned out possible to make the bot stateless, so no DB-like storage is required.&lt;br /&gt;
&lt;h3&gt;
Source code&lt;/h3&gt;
You can check the code on GitHub:&amp;nbsp;&lt;a href=&quot;https://github.com/npc/ant-lab&quot;&gt;https://github.com/npc/ant-lab&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
I may use it for other toolbelt-type tasks, hence the naming. For now, if you check &lt;a href=&quot;https://github.com/NPC/ant-lab/blob/master/index.js&quot;&gt;index.js&lt;/a&gt;, you&#39;ll see it performs a single meaningful task—if called on a certain URL (configured as “bot_invocation_path” in &lt;a href=&quot;https://github.com/NPC/ant-lab/blob/master/config.js&quot;&gt;config.js&lt;/a&gt;, it executes method &lt;b&gt;telegram.runInstagramBot()&lt;/b&gt;&amp;nbsp;from &lt;a href=&quot;https://github.com/NPC/ant-lab/blob/master/lib/telegram.js&quot;&gt;lib/telegram.js&lt;/a&gt;:&lt;br /&gt;
&lt;pre style=&quot;background: #000000; color: #d1d1d1;&quot;&gt;app&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;get&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; config&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;bot_invocation_path&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;request&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; response&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
  console&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: teal;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: teal;&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;--=== Telegram Instagram Bot triggered at &lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt; 
              &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;new&lt;/span&gt; Date&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;toISOString&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt; ===--&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
  telegram&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;runInstagramBot&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
  response&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;render&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;pages/trigger&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt; &lt;span style=&quot;color: #9999a9;&quot;&gt;// TODO: Render something useful&lt;/span&gt;
&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
The response is needed to tell the Cron service that everything is OK (200), it doesn&#39;t do anything else for now (as you can tell from my TODO comment). Otherwise Cron will notify me.&lt;br /&gt;
&lt;br /&gt;
Moving to&amp;nbsp;&lt;a href=&quot;https://github.com/NPC/ant-lab/blob/master/lib/telegram.js&quot;&gt;lib/telegram.js&lt;/a&gt;&amp;nbsp;you&#39;ll see that&amp;nbsp;runInstagramBot() makes a call to get updates chats—&lt;b&gt;telegramGetUpdatedChats()&lt;/b&gt;, which returns an Array of chat IDs in the callback.&lt;br /&gt;
&lt;br /&gt;
Then, if chat count is above zero, we retrieve Instagram media via &lt;b&gt;instagramGet()&lt;/b&gt;&amp;nbsp;function, and post all recent media (posted less than&amp;nbsp;&lt;b&gt;config.instagram.max_time_difference&lt;/b&gt; milliseconds ago), and post&amp;nbsp;&lt;b&gt;process.env.INSTAGRAM_MAX_MEDIA_COUNT&lt;/b&gt;&amp;nbsp;(default 5) of these images as links to each Telegram chat, by calling our &lt;b&gt;telegramPost()&lt;/b&gt; function.&lt;br /&gt;
&lt;br /&gt;
If no suitable media was found, the bot posts a random quip to the chat using&amp;nbsp;getNotFoundMessage() function (currently in Russian, I guess it would be nice to move these to config.js as well). The main point of these is for me to see that the bot is doing something even if there is nothing to post.&lt;br /&gt;
&lt;br /&gt;
All interactions with Telegram and Instagram are done via GET and POST calls to their open APIs, you can see which ones by following the code. Ping me if you think more explanations are in order.&lt;br /&gt;
&lt;br /&gt;
You&#39;ll note that there are debug mode statements, which ignore the list of Telegram chats, and make all posting to a specified chat ID—for testing I started a private chat with the bot (yes, it is that kind of bleak future where I talk to bots privately), and configured this chat ID for debug mode:&lt;br /&gt;
&lt;pre style=&quot;background: #000000; color: #d1d1d1;&quot;&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;config&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;bot_debug_mode&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;
 chatIDs &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;[&lt;/span&gt; config&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;telegram&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;debug_chat &lt;span style=&quot;color: #d2cd86;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt; &lt;span style=&quot;color: #9999a9;&quot;&gt;// Private chat for testing&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
And that&#39;s mostly it!&lt;br /&gt;
&lt;h3&gt;
Configuration&lt;/h3&gt;
For my purposes I decided that the bot should run twice a day, to post updates in the mornings and evenings. So I&#39;ve set the Cron to run it every 12 hours, and set&amp;nbsp;&lt;b&gt;config.instagram.max_time_difference&lt;/b&gt; to 12*60*60*1000 ms. Thus the bot only posts images which were posted since it was last run.&lt;br /&gt;
&lt;br /&gt;
All other meaningful configuration, including the URL that gets called (to sidestep potential DoS attacks, since that would simply stop my free Heroku host from working) is set in &lt;a href=&quot;https://github.com/NPC/ant-lab/blob/master/config.js&quot;&gt;config.js&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
You&#39;ll get Telegram API token when creating you bot on their site (very easy, just talk to the &lt;a href=&quot;https://core.telegram.org/bots#botfather&quot;&gt;BotFather&lt;/a&gt;), and I got my Instagram API token by looking it up in their &lt;a href=&quot;https://apigee.com/console/instagram&quot;&gt;API console&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
I found it very convenient to use&amp;nbsp;&lt;b&gt;process.env.*&lt;/b&gt; (Process module from Node.js)&amp;nbsp;to retrieve configuration from the environment. This allows me to share my source code, without risk to sensitive data, such as Telegram and Instagram API tokens, as these values are set on the server side (&lt;a href=&quot;https://devcenter.heroku.com/articles/config-vars&quot;&gt;this is how Heroku does it&lt;/a&gt;).&lt;br /&gt;
&lt;h3&gt;
Stateless Caveat&lt;/h3&gt;
One last note is that for Telegram&#39;s&amp;nbsp;&lt;b&gt;getUpdates&lt;/b&gt;&amp;nbsp;call to return anything, there should be recent messages in each chat. Otherwise the bot won&#39;t know the chat exists. This is a side effect of the bot&#39;s statelessness.&lt;br /&gt;
&lt;br /&gt;
This is not ideal—first of all, it means the bot should be allowed to see chat messages (see &lt;a href=&quot;https://core.telegram.org/bots#privacy-mode&quot;&gt;Privacy mode&lt;/a&gt;), or it will not get any updates at all. If there are no active discussions, Telegram won&#39;t report anything older than 3 days, so the bot will quietly “forget” about the chat. For my purposes this is perfectly fine, yet if you develop your own bot you may need to address this. This probably will require some storage bot-side, to remember which chats it was ever added to, and watch the response to Telegram&#39;s sendMessage call, to see whether all those chats are still valid.&lt;br /&gt;
&lt;h3&gt;
Conclusion&lt;/h3&gt;
This was a great exercise for me: the actual coding was fairly simple, yet I learnt a lot about setting up the tools and configuring their interaction. Plus, there is nothing like the pleasure of seeing your little bot, you baby, chirping in the chat twice a day, sharing links to photos that my friends posted :)&lt;br /&gt;
&lt;br /&gt;
Let me know if you have any questions, or if you notice any glaring mistakes in my source code.</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/4358495735026636487/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2016/01/a-simple-telegram-bot-with-nodejs.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/4358495735026636487'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/4358495735026636487'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2016/01/a-simple-telegram-bot-with-nodejs.html' title='A simple Telegram bot with Node.js'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8y0MJ8B0xKiW5FLg61DCyE-aX8s-uJ4T-K1S2FjfnqtTqjorLCJnikidqmvo4vILeUmLVqKgdTJdfEeweAtJsSD4o_ExcKQ-V7VzPok3KR7zfUkUga62wo1LRVC_Y6gbYmQ9AYEvAEg/s72-c/telegram-bot.jpg" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-4457680121269690843</id><published>2015-05-07T21:19:00.000+03:00</published><updated>2015-05-07T21:19:56.984+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="css"/><category scheme="http://www.blogger.com/atom/ns#" term="design"/><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="drupal"/><category scheme="http://www.blogger.com/atom/ns#" term="reading digest"/><category scheme="http://www.blogger.com/atom/ns#" term="testing"/><title type='text'>Reading Digest 05</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFYkm95XVT3d7eb678qaVNkDEqPmbhEjaVtHEJWJDPT0vz_y9TH8EW-WrQIibwbxBx9eWiauzlqZSHB6w8MX1OvaPEsumjtPtAFX17iPFeRmC2gZFsBVVmMoiIk5jzlODsHlmTzyy9fQ/s1600/pc_notes_phone.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFYkm95XVT3d7eb678qaVNkDEqPmbhEjaVtHEJWJDPT0vz_y9TH8EW-WrQIibwbxBx9eWiauzlqZSHB6w8MX1OvaPEsumjtPtAFX17iPFeRmC2gZFsBVVmMoiIk5jzlODsHlmTzyy9fQ/s1600/pc_notes_phone.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Sharing what impressed, inspired and made me think this week, even if to thank the authors for taking the time for putting their thoughts and experiences together.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://simpleprogrammer.com/2015/04/13/why-comments-are-stupid-a-real-example/&quot;&gt;Why Comments Are Stupid, a Real Example&lt;/a&gt;—OK, OK, the example is not very “real”, yet a good demonstration of ways to improve code readability. I usually err on the side of “too many comments”, especially when analyzing someone else&#39;s code. So it is a good reminder for me to be thoughtful about them—and perhaps improve the code itself instead. Comments are still good, if used well. If you never comment your code—ignore the article. I hate you :)&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://css-tricks.com/html-vs-body-in-css/&quot;&gt;HTML vs Body in CSS&lt;/a&gt;—hmm, dealing with these seems more like “This is how it&#39;s done!” than actually making sense. But oh well, I guess we just need to know and remember. A nice comment about relative font sizes, though, I do need to use those rem&#39;s more.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://kadavy.net/blog/posts/aa-testing/&quot;&gt;A/A Testing: How I increased conversions 300% by doing absolutely nothing&lt;/a&gt;—which sounds like an April Fool&#39;s joke (a well written one!), until you read into it. Takeaway—don&#39;t waste time on trendy techniques unless you understand what you&#39;re doing, and the statistics could mislead, especially without a large user-base (which is most of us, to be honest).&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.mediacurrent.com/blog/top-drupal-7-modules-final-edition&quot;&gt;Top Drupal 7 Modules: Final Edition&lt;/a&gt;—lately I&#39;ve been leaning more towards Wordpress for “standard” sites, since there&#39;s a lot to be said about simple tools for simple jobs (“don&#39;t use a cannon to shoot small birds”). Yet I may still go back to the powerful flexibility of Drupal if a problem requires it. Then I&#39;ll probably use a lot of the modules listed here. Nice to see some good old friends mentioned—we&#39;ve been through a lot together, eh?&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.designer-daily.com/brands-redesigned-by-hand-52369&quot;&gt;Brands redesigned by hand, an experiment in lettering&lt;/a&gt;—these look great! I mean, that&#39;s really bad. They&#39;re just… wrong! This is a good demonstration why thoughtful font usage matters—even when something is beautiful, it may still be completely inappropriate for your brand.&lt;br /&gt;
&lt;br /&gt;
And, finally, &lt;a href=&quot;http://www.fastcodesign.com/3044877/the-golden-ratio-designs-biggest-myth&quot;&gt;the golden ratio is a lie&lt;/a&gt;. I knew it!&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/4457680121269690843/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2015/05/reading-digest-05.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/4457680121269690843'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/4457680121269690843'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2015/05/reading-digest-05.html' title='Reading Digest 05'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFYkm95XVT3d7eb678qaVNkDEqPmbhEjaVtHEJWJDPT0vz_y9TH8EW-WrQIibwbxBx9eWiauzlqZSHB6w8MX1OvaPEsumjtPtAFX17iPFeRmC2gZFsBVVmMoiIk5jzlODsHlmTzyy9fQ/s72-c/pc_notes_phone.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-4583268073084742161</id><published>2015-05-01T23:46:00.000+03:00</published><updated>2015-05-01T23:46:23.241+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><title type='text'>Double Trouble: Two risky features come together for a conflict in JavaScript</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5nvrzVNvjd95Qdgnj4VMX9BTlE6QA0BPxgJznPPBl_FMW2vQSlInRsqZNyyrSSD7gg0dvWE4_YRy55Hlv0MOu09I2EtM2vdnc1wpByxok02LD-yER7M_hoCmPW8x_UKZFj900PPF3TA/s1600/under-the-hood.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5nvrzVNvjd95Qdgnj4VMX9BTlE6QA0BPxgJznPPBl_FMW2vQSlInRsqZNyyrSSD7gg0dvWE4_YRy55Hlv0MOu09I2EtM2vdnc1wpByxok02LD-yER7M_hoCmPW8x_UKZFj900PPF3TA/s1600/under-the-hood.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
On the value of being careful with modifying global scope. There is a code conflict I encountered recently when combining somebody else&#39;s JavaScript code with a 3rd party library. It didn&#39;t go well, and took time code-digging / stepping-through / debugging / tracing, until finally the cause became apparent.&lt;br /&gt;
&lt;br /&gt;
JavaScript in general is very flexible (beyond loose), which is reason to both love it (“With great power…”) and hate it (“…comes great responsibility”). But blaming one&#39;s tools isn&#39;t helpful when you need to get a job done.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
These are the two things that caused the conflict. Both are discouraged, but you won&#39;t understand why until you see them together.&lt;br /&gt;
&lt;h3&gt;
Array.prototype.[method]&lt;/h3&gt;
There is a very powerful ability in JavaScript to modify a prototype (a sample Object template similar to class in OOP languages) by adding new methods:&lt;br /&gt;
&lt;pre style=&quot;background: #000000; color: #d1d1d1;&quot;&gt;MyClass&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;prototype&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;newMethod &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
   &lt;span style=&quot;color: #9999a9;&quot;&gt;// New method for &quot;class&quot; MyClass&lt;/span&gt;
&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;
Then you can call this method on any object of MyClass. Sweet.&lt;br /&gt;
&lt;br /&gt;
Yet what then seems extra-powerful, is the ability to do the same with system classes. And, since (almost) everything is an object in JavaScript, you can add your own methods to String, Date, RegExp. This could really help &lt;i&gt;locally&lt;/i&gt; improve readability of your code, since instead of&amp;nbsp;&lt;b&gt;getPresidentNames(getAllNames())&lt;/b&gt; you could call &lt;b&gt;getAllNames().getPresidentNames()&lt;/b&gt;, potentially &lt;i&gt;chaining&lt;/i&gt; operations instead of &lt;i&gt;matrushka-dolling&lt;/i&gt; them.&lt;br /&gt;
&lt;br /&gt;
But modifying system objects like this is discouraged, because the change is global. Your added method will be visible to all of your code (which, in our day and age, 90% is made of code not written by you).&lt;br /&gt;
&lt;br /&gt;
In my case, Array object was expanded with &lt;b&gt;.max()&lt;/b&gt; and &lt;b&gt;.min()&lt;/b&gt; methods. This sounds useful, but…&lt;br /&gt;
&lt;h3&gt;
Array property iterator&lt;/h3&gt;
Here&#39;s another convenient feature—you can iterate over all of the object&#39;s properties:&lt;br /&gt;
&lt;pre style=&quot;background: #000000; color: #d1d1d1;&quot;&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; prop &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;in&lt;/span&gt; myObject&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
   console&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;myObject has property &lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&quot;&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; prop&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;
Very powerful, though potentially dangerous. If you run this in a controlled environment, where every single line of code was written by you, you&#39;ll get the list of properties that you&#39;ve yourself defined. It is a very nice and expected result.&lt;br /&gt;
&lt;br /&gt;
But what if someone redefined the object elsewhere?&lt;br /&gt;
&lt;br /&gt;
Custom objects—not a problem, especially if you use closures.&lt;br /&gt;
&lt;br /&gt;
System objects—not a problem… until somebody decides to add a method. Then you get list of properties and methods, including the newly added one.&lt;br /&gt;
&lt;br /&gt;
For arrays, iterating with &lt;b&gt;for(… in …)&lt;/b&gt; goes through the list of existing array indices. If you add methods—it will include them too. E.g. the list of values will be &quot;1&quot;, &quot;2&quot;, &quot;newMethod&quot;.&lt;br /&gt;
&lt;br /&gt;
The painful part (and that makes it hard to detect these kinds of issues) is that even if you make the change inside a closure, you&#39;re still modifying a global object, so you&#39;ll affect all of your code. Here&#39;s a simple Fiddle demonstrating this:&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;allowfullscreen&quot; frameborder=&quot;0&quot; height=&quot;300&quot; src=&quot;//jsfiddle.net/NPC42/ov3qxao1/embedded/&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;

&lt;br /&gt;
&lt;h3&gt;
What should we do?&lt;/h3&gt;
Two options.&lt;br /&gt;
&lt;br /&gt;
None of the above features are really damaging by itself. Your code will work fine if you do either. So, when a conflict happens, you can play the blame game (Don&#39;t &lt;i&gt;you&lt;/i&gt; expand prototypes! No, don&#39;t &lt;i&gt;you&lt;/i&gt; iterate over arrays as objects!).&lt;br /&gt;
&lt;br /&gt;
But that&#39;s not very productive.&lt;br /&gt;
&lt;br /&gt;
On the other hand—you can understand that both practices are risky, since you don&#39;t always have control over all the code. So just avoid these.&lt;br /&gt;
&lt;br /&gt;
For methods on global objects it is probably safer to use functions, if you really need to. They don&#39;t look as nice, but they are local to your closure, so—safe.&lt;br /&gt;
&lt;br /&gt;
For iterating over arrays, there are other methods (&lt;b&gt;for(i = 0; i &amp;lt; Array.length; i++)&lt;/b&gt;, or &lt;b&gt;Array.forEach()&lt;/b&gt;), whatever suits you. Or, if you are so adamant on using &lt;b&gt;for(… in Array)&lt;/b&gt;, then make sure to type-check to exclude functions (at least!).&lt;br /&gt;
&lt;br /&gt;
You&#39;ll figure it out :)&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/4583268073084742161/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2015/05/double-trouble-two-risky-features-come.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/4583268073084742161'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/4583268073084742161'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2015/05/double-trouble-two-risky-features-come.html' title='Double Trouble: Two risky features come together for a conflict in JavaScript'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5nvrzVNvjd95Qdgnj4VMX9BTlE6QA0BPxgJznPPBl_FMW2vQSlInRsqZNyyrSSD7gg0dvWE4_YRy55Hlv0MOu09I2EtM2vdnc1wpByxok02LD-yER7M_hoCmPW8x_UKZFj900PPF3TA/s72-c/under-the-hood.jpg" height="72" width="72"/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-2761101071660470614</id><published>2015-04-21T20:21:00.001+03:00</published><updated>2015-04-21T20:21:24.333+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="amcharts"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="micro-solution"/><category scheme="http://www.blogger.com/atom/ns#" term="svg"/><title type='text'>Micro-solution: Automatic Value Axes Offset in amCharts</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTguRZ7kFuQh6Zq01ncCJi59K2bp7-H9FVeqQlxYtEVdyFCtuExT_acZUg791ilN9vNXS_9bi41bqTqfO31stM1sQQjLyhkm2cn5S_R8Zab5Fj0XtMBNF08bwLQpl3AWZ3Rr9Iby80Og/s1600/bars-axes-logs.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTguRZ7kFuQh6Zq01ncCJi59K2bp7-H9FVeqQlxYtEVdyFCtuExT_acZUg791ilN9vNXS_9bi41bqTqfO31stM1sQQjLyhkm2cn5S_R8Zab5Fj0XtMBNF08bwLQpl3AWZ3Rr9Iby80Og/s1600/bars-axes-logs.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Working with &lt;a href=&quot;http://www.amcharts.com/&quot;&gt;amCharts&lt;/a&gt;&amp;nbsp;library for visualizing various report&#39;s data in &lt;a href=&quot;http://www.i-plansoftware.com/&quot;&gt;I-Plan Supply Chart Planning&lt;/a&gt; software, I came across a difficulty configuring multiple value axes for our specific case.&lt;br /&gt;
&lt;br /&gt;
amCharts is very flexible, allowing to set several axes, define their position (“left” or “right”), title, colour, min/max values, tick formatting etc. It even allows defining an offset (in pixels) to avoid overlap of axes.&lt;br /&gt;
&lt;br /&gt;
Yet in our case the reports are built by the users, various values assigned to different axes based on units, and can be aligned left or right at will. This means that a constant offset value simply doesn&#39;t cut it—if you have report values that are too wide they&#39;ll overlap, and if they&#39;re narrow—they will leave a gap.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7xAZO8lhuCOAeg1eN0-b9vIe6VypJpLjmwlK6vcrh1YyrejUacf-oi0qc04rttUTGYLzGoHsTI-HcvfL7XaylNQLuJztj2iBbqGoF3fct3fOGR26or7kVTnBMI6Zh6ebING0TIJxItQ/s1600/amcharts_overlap_or_gap.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7xAZO8lhuCOAeg1eN0-b9vIe6VypJpLjmwlK6vcrh1YyrejUacf-oi0qc04rttUTGYLzGoHsTI-HcvfL7XaylNQLuJztj2iBbqGoF3fct3fOGR26or7kVTnBMI6Zh6ebING0TIJxItQ/s1600/amcharts_overlap_or_gap.jpg&quot; height=&quot;176&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;b&gt;Life is like a box of axes with fixed offsets.&lt;br /&gt;Neither look good.&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
To test various permutations I created this&amp;nbsp;&lt;a href=&quot;http://jsfiddle.net/NPC42/5jxb3r91/&quot;&gt;fiddle&lt;/a&gt;&amp;nbsp;based on amChart&#39;s own &lt;a href=&quot;http://www.amcharts.com/demos/multiple-value-axes/&quot;&gt;demo&lt;/a&gt;. In the demo the value range is known for all axes, so it is simple to hand-pick the required offset. Yet if the values are outside of your control, you could get the picture on the right.&lt;br /&gt;
&lt;br /&gt;
Not nice.&lt;br /&gt;
&lt;br /&gt;
So, with the aid of extremely helpful&amp;nbsp;Martynas Majeris from amCharts support team, I set out to identify actual axis widths after they have been rendered, and automatically update the axes&#39; offsets.&lt;br /&gt;
&lt;br /&gt;
You can jump straight into the code:&lt;br /&gt;
&lt;pre style=&quot;background: #000000; color: #d1d1d1;&quot;&gt;&lt;span style=&quot;color: #9999a9;&quot;&gt;// Render chart (your code may vary)&lt;/span&gt;
chart&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;write&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;sChartID&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;

&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; oAxesOffsetPerPosition &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;

&lt;span style=&quot;color: #9999a9;&quot;&gt;// After chart is rendered, find value axes in the SVG&lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;// Using class names from http://www.amcharts.com/tutorials/css-class-names/&lt;/span&gt;
chart&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;valueAxes&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;forEach&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;oAxis&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; nAxisIndex&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
    chartElem&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;find&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;.value-axis-&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; oAxis&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;id&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;each&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
        &lt;span style=&quot;color: #9999a9;&quot;&gt;// amCharts has three elements per .value-axis-[axisId], find the one with labels&lt;/span&gt;
        &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;$&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;find&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;.amcharts-axis-label&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;length&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
            &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;!&lt;/span&gt;oAxesOffsetPerPosition&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;hasOwnProperty&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;oAxis&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;position&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;
                oAxesOffsetPerPosition&lt;span style=&quot;color: #d2cd86;&quot;&gt;[&lt;/span&gt;oAxis&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;position&lt;span style=&quot;color: #d2cd86;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;

            chart&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;valueAxes&lt;span style=&quot;color: #d2cd86;&quot;&gt;[&lt;/span&gt;nAxisIndex&lt;span style=&quot;color: #d2cd86;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;offset &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; oAxesOffsetPerPosition&lt;span style=&quot;color: #d2cd86;&quot;&gt;[&lt;/span&gt;oAxis&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;position&lt;span style=&quot;color: #d2cd86;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;

            oAxesOffsetPerPosition&lt;span style=&quot;color: #d2cd86;&quot;&gt;[&lt;/span&gt;oAxis&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;position&lt;span style=&quot;color: #d2cd86;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;+=&lt;/span&gt; $&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #008c00;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;getBBox&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;width &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
         &lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;
    &lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;

&lt;span style=&quot;color: #9999a9;&quot;&gt;// Redraw chart with updated .valueAxes data&lt;/span&gt;
chart&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;validateData&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
The idea is very simple, though has some finer points:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Identifying the axes:&lt;/b&gt; Thankfully, since v3.12 amCharts support including &lt;a href=&quot;http://www.amcharts.com/tutorials/css-class-names/&quot;&gt;class names&lt;/a&gt; into the generated SVG—otherwise it would be near impossible to find the value axes. Make sure to enable these. The next hurdle is that for a given axis ID there are three (!) SVG elements with the corresponding class—this includes the grid lines etc. The element we need is the one that contains “[prefix]-axis-label”&amp;nbsp;elements.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Determine axis width:&lt;/b&gt;&amp;nbsp;My go-to function $.outerWidth() doesn&#39;t work on SVG elements, so using &lt;b&gt;.getBBox().width&lt;/b&gt; instead. Thank you, &lt;a href=&quot;http://stackoverflow.com/a/11867715/253974&quot;&gt;StackOverflow&lt;/a&gt; :)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Accumulate width per axis position:&lt;/b&gt; This is straightforward, I created an object with properties for “left” and “right” positions, and increment them by each axis.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Update the chart:&lt;/b&gt; After a property of the amCharts&#39; “chart” object is updated, I call &lt;a href=&quot;http://docs.amcharts.com/3/javascriptcharts/AmChart#validateData&quot;&gt;.validateData()&lt;/a&gt;. Interestingly, calling &lt;a href=&quot;http://docs.amcharts.com/3/javascriptcharts/AmChart#validateNow&quot;&gt;.validateNow(true, true)&lt;/a&gt; causes the chart to visibly jump around—so .validateData() is &lt;i&gt;empirically&lt;/i&gt; better.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
After all that, our mission is accomplished:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2EUUUW5K_6DeZaDdhqv2gbvxahEKU20X76SiS0zbH3i3b1S2qqIdrnqOVanpsVulE9w0GhYYQLPcRNGFTcJxg6tk1zNfTgl28M7Ng58Bq0mG5mF7heuHVInVE_IBFUObcCOdHSGTGQQ/s1600/amcharts_multiple_axes_1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2EUUUW5K_6DeZaDdhqv2gbvxahEKU20X76SiS0zbH3i3b1S2qqIdrnqOVanpsVulE9w0GhYYQLPcRNGFTcJxg6tk1zNfTgl28M7Ng58Bq0mG5mF7heuHVInVE_IBFUObcCOdHSGTGQQ/s1600/amcharts_multiple_axes_1.png&quot; height=&quot;223&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
And even weirdo users can get their way now. At least they are not playing with real axes—that could be dangerous:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyL_O9-wXXyyQcafEVKa0Jn0nib97btrmydCuVWdfYh1Lr-KX4stL4WGDhIg1rm92UpPGWZXBBv71FLYnFaT2_QOX2imlrsI9PHV-MU1SdsLvUsH8hkQc6b8YLmgR4l9D7pt2_1xi68w/s1600/amcharts_multiple_axes_2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyL_O9-wXXyyQcafEVKa0Jn0nib97btrmydCuVWdfYh1Lr-KX4stL4WGDhIg1rm92UpPGWZXBBv71FLYnFaT2_QOX2imlrsI9PHV-MU1SdsLvUsH8hkQc6b8YLmgR4l9D7pt2_1xi68w/s1600/amcharts_multiple_axes_2.png&quot; height=&quot;222&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Take care!&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/2761101071660470614/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2015/04/micro-solution-automatic-value-axes-offset-amcharts.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/2761101071660470614'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/2761101071660470614'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2015/04/micro-solution-automatic-value-axes-offset-amcharts.html' title='Micro-solution: Automatic Value Axes Offset in amCharts'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTguRZ7kFuQh6Zq01ncCJi59K2bp7-H9FVeqQlxYtEVdyFCtuExT_acZUg791ilN9vNXS_9bi41bqTqfO31stM1sQQjLyhkm2cn5S_R8Zab5Fj0XtMBNF08bwLQpl3AWZ3Rr9Iby80Og/s72-c/bars-axes-logs.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-6795002444229609232</id><published>2015-04-14T21:09:00.002+03:00</published><updated>2016-01-12T21:25:25.850+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="crossrider"/><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="extension"/><category scheme="http://www.blogger.com/atom/ns#" term="html"/><category scheme="http://www.blogger.com/atom/ns#" term="jasmine"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="qunit"/><category scheme="http://www.blogger.com/atom/ns#" term="testing"/><title type='text'>JavaScript Unit Testing in Crossrider Browser Extensions</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHHZTQRX7jeVrTG6vvnL-4-YXkPqFUP4G5-Fq8HnsreOkHSE2CrXjdWM4zA855yvn-bZOTDkcxkFOMM1BvCgWj2SXfTOUzcyPUio3vz1s78EmbWrRo33SOS3_-ITl6KvEYJsm5pcRWkQ/s1600/measuring-tools.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHHZTQRX7jeVrTG6vvnL-4-YXkPqFUP4G5-Fq8HnsreOkHSE2CrXjdWM4zA855yvn-bZOTDkcxkFOMM1BvCgWj2SXfTOUzcyPUio3vz1s78EmbWrRo33SOS3_-ITl6KvEYJsm5pcRWkQ/s1600/measuring-tools.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;Note:&lt;/b&gt;&amp;nbsp;Please see my&amp;nbsp;&lt;a href=&quot;http://www.amaslo.com/2016/01/crossrider-not-recommended-for-cross-browser-extensions.html&quot;&gt;update on Crossrider status&lt;/a&gt;&amp;nbsp;(12 Jan 2016).&lt;br /&gt;
&lt;br /&gt;
Here&#39;s the approach I found looking for a way to implement unit tests for my &lt;a href=&quot;http://www.amaslo.com/2015/03/developing-javascript-browser-extensions-with-crossrider.html&quot;&gt;JavaScript browser extension&lt;/a&gt; (written using &lt;a href=&quot;https://crossrider.com/&quot;&gt;Crossrider&lt;/a&gt; framework). The method is quite straightforward, yet still required me to do some research and testing. This approach in theory is agnostic of the testing library you use, or at least it should be. I will demonstrate it with both &lt;a href=&quot;https://qunitjs.com/&quot;&gt;QUnit&lt;/a&gt; and &lt;a href=&quot;http://jasmine.github.io/&quot;&gt;Jasmine&lt;/a&gt;.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;h4&gt;
Setup&lt;/h4&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUtUCGOPY4O2DqJ4lRGye9_GIRcyBzH3rwgrc2KYqAh3fyTKzEScgfU88Z-QRgw_QIGuASknGEoSW7sGexPD3HGBspdZwNlFmxG5qayDemHfykiNt3FictfxjpJ455gYppF5Zij2w8KA/s1600/test-extension-file-structure.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUtUCGOPY4O2DqJ4lRGye9_GIRcyBzH3rwgrc2KYqAh3fyTKzEScgfU88Z-QRgw_QIGuASknGEoSW7sGexPD3HGBspdZwNlFmxG5qayDemHfykiNt3FictfxjpJ455gYppF5Zij2w8KA/s1600/test-extension-file-structure.png&quot; /&gt;&lt;/a&gt;Let&#39;s create a basic browser extension in Crossrider, uploading the necessary library files as resources. Your folder structure may vary (“Show me your file structure and I will tell you who you are” :)), you can see how I decided to do it on the right.&lt;br /&gt;
&lt;br /&gt;
Everything related to unit tests is inside “testing” sub-folder, so it doesn&#39;t mix with whatever potential resources will be added for the extension itself.&lt;br /&gt;
&lt;br /&gt;
Files &lt;b&gt;jasmine-tests.js&lt;/b&gt; and &lt;b&gt;qunit-tests.js&lt;/b&gt; contain the testing code that I wrote—I&#39;ll show the contents of these files below.&lt;br /&gt;
&lt;br /&gt;
Note that files &lt;b&gt;extension.js&lt;/b&gt; and &lt;b&gt;background.js&lt;/b&gt; are required by the extension (&lt;a href=&quot;http://www.amaslo.com/2015/03/developing-javascript-browser-extensions-with-crossrider.html&quot;&gt;as I wrote earlier&lt;/a&gt;), these files contain all of the extension logic, and load additional JS resources as necessary.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Triggering Condition&lt;/h4&gt;
Now, the key issue is that JS unit tests are usually run inside of an HTML harness—it is used to store the HTML markup necessary for the tests (if your JavaScript is presentation-heavy, which usually is the case), and also it is used to output test results.&lt;br /&gt;
&lt;br /&gt;
Yet the extension doesn&#39;t run on your given HTML file, it runs in the context of each page open in the browser (speaking of the code inside &lt;b&gt;extension.js&lt;/b&gt; file—background.js scope is a different matter, I&#39;ll talk about it below).&lt;br /&gt;
&lt;br /&gt;
So here&#39;s the simple yet robust method that I&#39;ve used—to stop the tests from running on every page, I check that there is a very specific string contained in the page address. For example, check that there is “test-crossrider” string at the end of the URL. Then I can trigger unit tests by opening, e.g.,&amp;nbsp;http://www.amaslo.com/?test-crossrider in my browser (with the extension installed).&lt;br /&gt;
&lt;br /&gt;
Here&#39;s the code I&#39;ve placed in &lt;b&gt;extension.js&lt;/b&gt;:&lt;br /&gt;
&lt;pre style=&quot;background: #000000; color: #d1d1d1;&quot;&gt;&lt;span style=&quot;color: #9999a9;&quot;&gt;/*&lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;&amp;nbsp;*  extension.js&lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;&amp;nbsp;*  Testing BDD approach with Crossrider Extensions&lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;&amp;nbsp;*/&lt;/span&gt;

&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; bRunTests &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #0f4d75;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt; &lt;span style=&quot;color: #9999a9;&quot;&gt;// Allows disabling tests in production release&lt;/span&gt;

appAPI&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;ready&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;$&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
    &lt;span style=&quot;color: #9999a9;&quot;&gt;// Unit Tests&lt;/span&gt;
    &lt;span style=&quot;color: #9999a9;&quot;&gt;// Run with e.g. http://www.amaslo.com/?test-crossrider&lt;/span&gt;
    &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;bRunTests &lt;span style=&quot;color: #d2cd86;&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; appAPI&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;isMatchPages&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;*test-crossrider&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
     &lt;span style=&quot;color: #9999a9;&quot;&gt;// QUnit&lt;/span&gt;
     &lt;span style=&quot;color: #9999a9;&quot;&gt;//appAPI.resources.includeJS(&#39;testing/qunit-tests.js&#39;);&lt;/span&gt;
     
     &lt;span style=&quot;color: #9999a9;&quot;&gt;// Jasmine&lt;/span&gt;
     appAPI&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;resources&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;includeJS&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;testing/jasmine-tests.js&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
    &lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;
    
    &lt;span style=&quot;color: #9999a9;&quot;&gt;// This function will be tested&lt;/span&gt;
    &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt; funcForTest&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;sInput&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
     &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #0f4d75;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
    &lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;
&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
Hopefully it is self-documented enough, yet what happens is if the page address matches, and the tests are enabled—corresponding JS file is included and run.&lt;br /&gt;
&lt;br /&gt;
Simple.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Actual Tests&lt;/h4&gt;
QUnit tests:&lt;br /&gt;
&lt;pre style=&quot;background: #000000; color: #d1d1d1;&quot;&gt;&lt;span style=&quot;color: #9999a9;&quot;&gt;/*&lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;&amp;nbsp;*   Collection of Unit Tests&lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;&amp;nbsp;*  Using QUnit&lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;&amp;nbsp;*/&lt;/span&gt;

&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
 &lt;span style=&quot;color: #9999a9;&quot;&gt;// Testing library&lt;/span&gt;
 appAPI&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;resources&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;includeCSS&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;testing/qunit/qunit-1.18.0.css&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
 appAPI&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;resources&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;includeJS&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;testing/qunit/qunit-1.18.0.js&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
 
 &lt;span style=&quot;color: #9999a9;&quot;&gt;// This will keep the actual page still displayed below the report&lt;/span&gt;
 $&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;prepend&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&amp;lt;div id=&quot;qunit&quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div id=&quot;qunit-fixture&quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
 
 QUnit&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;Set of Tests Description&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;assert&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
  &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; value &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;hello&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
  
  assert&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;equal&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;value&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; &lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;hello&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; &lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;Expecting value to be hello&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
  assert&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;ok&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;funcForTest&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;value&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; &lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;funcForTest() should return true&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
 &lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
Which results in the following output on the page:&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1OoHSlv2Sol-lAfhGsQWMiWDhAjUAKcggTvnAbmulKB2Lt1295m-ozNqNfbPkpIHG1cKhyphenhyphenZA2uY0qYNRlqOSZwwL27hCjaCHZgLx0XFHYwsslXdKf1eQEZbmGIAj6x_U3jw0Y1qPbFA/s1600/extension-qunit-output.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;131&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1OoHSlv2Sol-lAfhGsQWMiWDhAjUAKcggTvnAbmulKB2Lt1295m-ozNqNfbPkpIHG1cKhyphenhyphenZA2uY0qYNRlqOSZwwL27hCjaCHZgLx0XFHYwsslXdKf1eQEZbmGIAj6x_U3jw0Y1qPbFA/s1600/extension-qunit-output.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
And for Jasmine (which I frankly prefer—it feels less like robo-talk, yet this is a matter of personal preference—definitely outside of this article&#39;s scope):&lt;br /&gt;
&lt;pre style=&quot;background: #000000; color: #d1d1d1;&quot;&gt;&lt;span style=&quot;color: #9999a9;&quot;&gt;/*&lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;&amp;nbsp;*   Collection of Unit Tests&lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;&amp;nbsp;*  Using Jasmine&lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;&amp;nbsp;*/&lt;/span&gt;

&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
 &lt;span style=&quot;color: #9999a9;&quot;&gt;// Testing library&lt;/span&gt;
 appAPI&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;resources&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;includeCSS&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;testing/jasmine/jasmine.css&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
 appAPI&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;resources&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;includeJS&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;testing/jasmine/jasmine.js&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
 appAPI&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;resources&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;includeJS&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;testing/jasmine/jasmine-html.js&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
 appAPI&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;resources&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;includeJS&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;testing/jasmine/boot.js&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
 
 &lt;span style=&quot;color: #9999a9;&quot;&gt;// Clean the document&lt;/span&gt;
 $&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;html&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
 
 describe&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;Set of Tests&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
  &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; value&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
  
  beforeEach&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
   value &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;hello&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
  &lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
  
  it&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;works&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
   expect&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;value&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;toBe&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;hello&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
  &lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
  
  it&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;calls functions&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
   expect&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;funcForTest&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;value&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;toBe&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0f4d75;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
  &lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
 &lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
Yielding:&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhapn9sOBVUk_hOkkIfcQ5UPGy_RtPoz1Pr92N9PhGVHzojGPTLemtjg4f1_s0K1-E6v0dKY-MJWc4a3ImeuAEh4AqpjNbM1fY73oFXLcRc1MTNLnlxmgq3qd1Acw8J_RW0uq9QWsTMTg/s1600/extension-jasmine-output.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;97&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhapn9sOBVUk_hOkkIfcQ5UPGy_RtPoz1Pr92N9PhGVHzojGPTLemtjg4f1_s0K1-E6v0dKY-MJWc4a3ImeuAEh4AqpjNbM1fY73oFXLcRc1MTNLnlxmgq3qd1Acw8J_RW0uq9QWsTMTg/s1600/extension-jasmine-output.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Sometimes I need to refresh the page a couple of times for Jasmine report to show up. This may be linked with extension loading / running, and doesn&#39;t really cause any inconvenience.&lt;br /&gt;
&lt;br /&gt;
Both QUnit and Jasmine tests above are identical setup-wise—include library files, do whatever needs to be done with the actual page (for example just wipe it as I do for Jasmine, or append/prepend necessary markup), which will depend on what your extension does, and running the tests.&lt;br /&gt;
&lt;br /&gt;
You&#39;ll notice that all unit tests are inside a closure (i.e. &lt;b&gt;(function() { ... })();&lt;/b&gt;), this is basic variable and function scope hygiene. The functions defined in &lt;b&gt;extension.js&lt;/b&gt; file (or the files it loads prior to running the tests) will be available in the tests&#39; scope.&lt;br /&gt;
&lt;br /&gt;
And… that&#39;s it. Really.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Real-life Tests&lt;/h4&gt;
Of course, the above tests are extremely primitive. Checking a variable&#39;s value, and a function&#39;s return value. These only demonstrate how to incorporate unit tests in a browser extension, trigger them and view the report.&lt;br /&gt;
&lt;br /&gt;
In your actual, down to Earth, real-life code you&#39;ll need to employ a lot more kung-fu from your library of choice.&lt;br /&gt;
&lt;br /&gt;
For example, since my extension works with Basecamp pages, I need to have corresponding HTML markup to test the JavaScript with. Instead of depending on actual Basecamp page, which will always have changing list of todo&#39;s, I&#39;ve snipped a pre-defined portion of the page and stored it in my Resources under &lt;b&gt;../testing/3rd-party/bcx.html&lt;/b&gt;. Then I can include this markup in the tests page (any page!) before the tests where I need it (using Jasmine):&lt;br /&gt;
&lt;pre style=&quot;background: #000000; color: #d1d1d1;&quot;&gt;describe&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;BCX Todos&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
 beforeEach&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
  &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; sHtml &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; appAPI&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;resources&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;get&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;testing/3rd-party/bcx.html&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
  $&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&amp;lt;div id=&quot;rm-test-bcx&quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;appendTo&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;html&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;sHtml&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
  &lt;span style=&quot;color: #9999a9;&quot;&gt;// ...&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
Just don&#39;t forget to tear it down in afterEach() call, so that subsequent tests start from the clean slate.&lt;br /&gt;
&lt;br /&gt;
For mimicking API calls you can use things like spyOn([object], [method]).and.callFake([function]), for testing asynchronous logic you&#39;ll use the “done()” callback passed into the it() statement, and so on. There&#39;s a lot to figure out, but this is part of standard unit code logic.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Testing Background and Popup Scopes&lt;/h4&gt;
A brief note on &lt;b&gt;background.js&lt;/b&gt; and &lt;b&gt;popup.html&lt;/b&gt;. These contain extension code that doesn&#39;t run on a given page, so testing them could be tricky.&lt;br /&gt;
&lt;br /&gt;
Depending on your situation, may I suggest minimizing the logic actually stored in &lt;b&gt;background.js&lt;/b&gt;, and instead move everything to separate resource files (*.js). Then these files can be included and validated in unit tests.&lt;br /&gt;
&lt;br /&gt;
For example, in my extension there is a lot of interaction with Roadmap API, and this is used both from &lt;b&gt;extension.js&lt;/b&gt; and &lt;b&gt;background.js&lt;/b&gt;. I chose to put all corresponding methods in file rm_api.js, and this file is then included as needed, in &lt;b&gt;extension.js&lt;/b&gt;:&lt;br /&gt;
&lt;pre style=&quot;background: #000000; color: #d1d1d1;&quot;&gt;appAPI&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;resources&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;includeJS&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;js/rm_api.js&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
Or in &lt;b&gt;background.js&lt;/b&gt; (since &lt;b&gt;appAPI.resources.includeJS&lt;/b&gt; isn&#39;t supported there):&lt;br /&gt;
&lt;pre style=&quot;background: #000000; color: #d1d1d1;&quot;&gt;$&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;globalEval&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;appAPI&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;resources&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;get&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;js/rm_api.js&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
This even avoids code repetition, so win-win. Still, I feel that this approach is not ideal. If you have better ideas—I&#39;d love to hear them.&lt;br /&gt;
&lt;br /&gt;
Regarding &lt;b&gt;popup.html&lt;/b&gt; scope—I have no solution for now, sadly. This part of code corresponds to the popup shown on pressing the extension&#39;s button in the browser bar, and this functionality is still very limited. Neither &lt;b&gt;appAPI.resources.includeJS&lt;/b&gt; nor &lt;b&gt;appAPI.resources.get&lt;/b&gt; are supported in this scope, so I see no way to load additional code files into it. I guess this logic will have to be tested manually, until someone comes up with a wonderful solution.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Conclusion (and a free advice)&lt;/h4&gt;
So, testing your extensions requires an adjustment of mindset, yet it is still possible, and not overly complicated, except for some nuances.&lt;br /&gt;
&lt;br /&gt;
If you allow me to share one advice—think about unit tests before you write your code. Not after. Unless you prefer to learn the hard way. Like I did.&lt;br /&gt;
&lt;br /&gt;
The reason is obvious in hindsight—structure and quality of your code is defined by necessity to call specific functions, test branches of logic, validate responses. Functions, methods, objects will almost naturally start forming into units with clearly divided responsibilities, complex spaghetti code will split into simpler pieces, and obscure solutions will look even less attractive—before you undertake to implement them!&lt;br /&gt;
&lt;br /&gt;
Yes, it will take time. Yet ultimately it is a good thing. Even if tests don&#39;t “catch” all of the future issues, having a well-structured source code is a gift for the future “you”.&lt;br /&gt;
&lt;br /&gt;
You&#39;ll thank yourself, trust me.&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/6795002444229609232/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2015/04/javascript-unit-testing-in-crossrider.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/6795002444229609232'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/6795002444229609232'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2015/04/javascript-unit-testing-in-crossrider.html' title='JavaScript Unit Testing in Crossrider Browser Extensions'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHHZTQRX7jeVrTG6vvnL-4-YXkPqFUP4G5-Fq8HnsreOkHSE2CrXjdWM4zA855yvn-bZOTDkcxkFOMM1BvCgWj2SXfTOUzcyPUio3vz1s78EmbWrRo33SOS3_-ITl6KvEYJsm5pcRWkQ/s72-c/measuring-tools.jpg" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-7201374915700885702</id><published>2015-03-11T22:29:00.001+02:00</published><updated>2016-01-12T21:24:55.837+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="crossrider"/><category scheme="http://www.blogger.com/atom/ns#" term="css"/><category scheme="http://www.blogger.com/atom/ns#" term="extension"/><category scheme="http://www.blogger.com/atom/ns#" term="html"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="tools"/><title type='text'>Developing browser extensions using JavaScript with Crossrider framework</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaIlPnSvDp_cGIalIw0-27p8eFbHdDR16qd581HEG3XLjbFDslnYWoKu7I0aiXxjR2eU0pResih5jn1w_Hw6bXbgiMR3A6YHrzW6M9fiyXG8iKUkxN9HHkAIf7Eam0SX45hz42RA2I3Q/s1600/cogs.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaIlPnSvDp_cGIalIw0-27p8eFbHdDR16qd581HEG3XLjbFDslnYWoKu7I0aiXxjR2eU0pResih5jn1w_Hw6bXbgiMR3A6YHrzW6M9fiyXG8iKUkxN9HHkAIf7Eam0SX45hz42RA2I3Q/s1600/cogs.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;b&gt;Note:&lt;/b&gt; Please see my &lt;a href=&quot;http://www.amaslo.com/2016/01/crossrider-not-recommended-for-cross-browser-extensions.html&quot;&gt;update on Crossrider status&lt;/a&gt;&amp;nbsp;(12 Jan 2016).&lt;br /&gt;
&lt;br /&gt;
As developers (or humans) we need to balance our skills. Sharp focus is valuable, yet tunnel-visioning oneself is not a good idea — there&#39;s so much to learn!&lt;br /&gt;
&lt;br /&gt;
While honing my HTML/CSS/JS kung-fu, I was unexpectedly tasked with something new. We needed to create a browser extension to go with Roadmap, a product our company works on.&lt;br /&gt;
&lt;br /&gt;
A completely new area — or so I thought. Some searching showed a simpler path. I could create extensions with my existing experience. Even more — those extensions could share a (more or less) common code base across all mainstream browsers.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
I do not intend to do a full comparison of possible frameworks. When we made our choice a year ago one company stood out — &lt;a href=&quot;http://crossrider.com/developers/&quot;&gt;Crossr&lt;span id=&quot;goog_7767603&quot;&gt;&lt;/span&gt;&lt;span id=&quot;goog_7767604&quot;&gt;&lt;/span&gt;ider&lt;/a&gt;. After having developed (as I &lt;a href=&quot;http://www.amaslo.com/2014/09/preserving-html-input-values-javascript.html&quot;&gt;mentioned before&lt;/a&gt;), tested, deployed and updated an extension that runs on Chrome, Firefox and Safari, I have to say that Crossrider delivers on the promise of, quoting their front page, &amp;nbsp;“Cross Browser Extensions in Minutes”.&lt;br /&gt;
&lt;br /&gt;
Any serious logic will need more time, sure, but the core can be up and running in minutes. Bonus part — actual development is done using my (currently) favorite JavaScript!&lt;br /&gt;
&lt;br /&gt;
Sold. Here are some notes and observations from this experience.&lt;br /&gt;
&lt;h3&gt;
&lt;/h3&gt;
&lt;h3&gt;
The Task&lt;/h3&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyplLu8p4GLnFW2ubeSEvJ1pTeatPrBLoyToWcEIp7Oz5Q7UVezOOL_XgrwEobr5Eka0yD9Im2lGNL_y0V_9XPVbrMrAQyScDMMiqD9h_u-GXH0N2BHeY9kU1xOvK7o59h5O-ya_0wYA/s1600/promotional-image.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;160&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyplLu8p4GLnFW2ubeSEvJ1pTeatPrBLoyToWcEIp7Oz5Q7UVezOOL_XgrwEobr5Eka0yD9Im2lGNL_y0V_9XPVbrMrAQyScDMMiqD9h_u-GXH0N2BHeY9kU1xOvK7o59h5O-ya_0wYA/s1600/promotional-image.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Our extension allows accessing Roadmap&#39;s data and functions (e.g. task start dates, multiple assignments, estimations, time tracking) when viewing to-do items on integrated 3rd-party sites — Basecamp (New and Classic) to start with, with more to come.&lt;br /&gt;
&lt;br /&gt;
You can see (or use, if you register) the result here: &lt;a href=&quot;https://chrome.google.com/webstore/detail/roadmap/ppcdhlicbeamihibghpgknfmonbhmnii&quot;&gt;Roadmap Extension in Chrome Web Store&lt;/a&gt;. Note that the visual style wasn&#39;t developed by me, except for a few personal minor touches it was provided by the skillful Roadmap team. My work was to implement the extension: lock, stock and barrel. I mean — markup, style and logic.&lt;br /&gt;
&lt;h3&gt;
&lt;/h3&gt;
&lt;h3&gt;
Features &amp;amp; Process&lt;/h3&gt;
Crossrider is, in layman terms, a wrapper around your JavaScript code with a consistent set of API methods. For each browser the wrapper&#39;s implementation could be different, yet it is transparent to our code. The API methods cover most needs for interacting with browser tabs, loaded pages, network requests etc.&lt;br /&gt;
&lt;br /&gt;
This is where it was a discovery process for me: you can&#39;t simply bundle all your logic in the same source code, browsers are more nuanced than that. Crossrider introduces three “scopes”, which manage different functional areas of your extension.&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2WHTFinM9EOYjVB5Krg7eQJMctptMn3QrK32jNgvxACP-d7SWROoUUdWm9cQMeKpqftE0CmhaRHeNTfOq-LdxSwS6f1QtJrdsxcWKGvrsroXzyxwdTrkv7AzNijdtAS4z0DCQyP10rA/s1600/rm_config_popup.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2WHTFinM9EOYjVB5Krg7eQJMctptMn3QrK32jNgvxACP-d7SWROoUUdWm9cQMeKpqftE0CmhaRHeNTfOq-LdxSwS6f1QtJrdsxcWKGvrsroXzyxwdTrkv7AzNijdtAS4z0DCQyP10rA/s1600/rm_config_popup.png&quot; width=&quot;316&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Configuration popup &lt;br /&gt;
allows setting global values used across tabs.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;b&gt;“Page”&lt;/b&gt; scope — JavaScript in this scope gets injected into any page that the browser opens. Here you can have logic to manipulate the DOM — add, remove, modify on-page elements; add user event handlers, inject custom styles, and so on.&lt;br /&gt;
&lt;br /&gt;
Basically, this part of code handles everything that happens on the page. Any page you visit — browser loads it first, then Crossrider injects and runs your code. You can check if this is the page you need (by URL or any other on-page criteria) and do what you need with it.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;“Background”&lt;/b&gt; scope performs tasks that are outside of the page context, and are instead “closer” to the browser. For example — manipulating browser tabs, monitoring network requests (a very neat and powerful feature!), configuring display of browser button.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;“Popup”&lt;/b&gt; scope — speaking of browser buttons, pressing on one opens a special HTML page, which is defined in this “popup” scope. This feature is quite limited, yet still needed to provide a visible way to configure your extension.&lt;br /&gt;
&lt;br /&gt;
While these scopes are separated by their nature, Crossrider offers a handy messaging API, which allows sending data-loaded messages between scopes. For example, if background scope of Roadmap extension detects an “update” network request from Basecamp New, then it tells the page scope to check for changes on the page — since it is possible that new todos were added.&lt;br /&gt;
&lt;br /&gt;
All the API is &lt;a href=&quot;http://docs.crossrider.com/&quot;&gt;neatly documented&lt;/a&gt;, and the actual development happens in Crossrider&#39;s online IDE, which is able to connect to already installed extension in the same browser and update it as needed (except for Safari and Internet Explorer — below I&#39;ll share my thoughts on browsers). It is possible to add resource files (you may need it to include CSS, HTML or images, and to modularize your JS code), and in general the IDE is on the simple side, but it does its job. There&#39;s even integration with JSHint, which warns about most obvious errors before pushing code update to the extension.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv2ywFuZLZkystYiHkdS41BFTRRw4rRAMrbB2KkK8-UAeLOGk1SkrRoApSiBiaQv8ML6rMKbkgYZ8PQfWOdtkS8Yoyznh0vs6PCACVIcylig5aFJRGK1CXTPyKIWx_VRJNn_flMMGG8w/s1600/rm_ext_IDE.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;215&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv2ywFuZLZkystYiHkdS41BFTRRw4rRAMrbB2KkK8-UAeLOGk1SkrRoApSiBiaQv8ML6rMKbkgYZ8PQfWOdtkS8Yoyznh0vs6PCACVIcylig5aFJRGK1CXTPyKIWx_VRJNn_flMMGG8w/s1600/rm_ext_IDE.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;The IDE. &lt;br /&gt;
It is also possible to configure a “Debug Mode”, &lt;br /&gt;
which allows editing files using your editor of choice, &lt;br /&gt;
yet I didn&#39;t bother with it&amp;nbsp;since the stock IDE works for me.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;
&lt;/h3&gt;
&lt;h3&gt;
Roadmap Extension&lt;/h3&gt;
While figuring everything out took a while, the extension itself is fairly simple.&lt;br /&gt;
&lt;br /&gt;
When a page loads, the extension checks whether it is being run on either of the two Basecamp sites. If yes — it detects the todo items are shown on the page, sends an API request to the Roadmap server, and displays the necessary information.&lt;br /&gt;
&lt;br /&gt;
To start with, it adds neat “R” icons to each todo that RM knows about. Clicking on these opens a popup with detailed todo information, and it is possible to edit this data, start / stop a timer, or log worked time for the task.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-pnLNZvReor5Osu_8BeXjFAJ4JcBZdzCkfbFqRLRfYCfPg_AM4xo1POeZrieA1yYR72K-WXZOVOcn0Z8Ne-d6w4A2UAF3Fw4zX11bY1ZGP5KxpRoyVuRRmnSIgc61TV_SjhohaMZGYg/s1600/rm_bcx_integration.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;295&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-pnLNZvReor5Osu_8BeXjFAJ4JcBZdzCkfbFqRLRfYCfPg_AM4xo1POeZrieA1yYR72K-WXZOVOcn0Z8Ne-d6w4A2UAF3Fw4zX11bY1ZGP5KxpRoyVuRRmnSIgc61TV_SjhohaMZGYg/s1600/rm_bcx_integration.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;The red icon stands for “running timer”. &lt;br /&gt;
The todo popup shows minimal required data “at a glance”, &lt;br /&gt;
allowing to go directly to detailed page in Roadmap itself.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
All of this requires quite a lot of user interaction, a number of API requests to the server etc, but the pleasing outcome is that it works.&lt;br /&gt;
&lt;h3&gt;
&lt;/h3&gt;
&lt;h3&gt;
Browser Support&lt;/h3&gt;
Crossrider claims support for desktop versions of Chrome, Firefox, Safari and Internet Explorer. In my experience this is true, but there are nuances to be found with each.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Firefox&lt;/b&gt; has been the best one to work with. The extension “just runs”, not compatibility issues or any such thing. The browser itself is democratic, not trying to limit how you install your extension or what you do with it.&lt;br /&gt;
&lt;br /&gt;
Yet one significant weakness is that currently it isn&#39;t possible to publish Crossrider extensions to &lt;a href=&quot;https://addons.mozilla.org/&quot;&gt;Mozilla Addon Directory&lt;/a&gt;. which is a huge shame. Extensions fail automatic checks performed on submission, and, having gone through this process myself, I see that the complaints aren&#39;t about my code — they are about the code provided as part of Crossrider framework, and thus out of our control. Crossrider team is aware of this, yet it is hard to say whether any progress is being worked on in this regard.&lt;br /&gt;
&lt;br /&gt;
One more problem that I found with Firefox is an incorrect implementation of Content Security Policy (CSP), which could be problematic in some cases. Briefly — same-URL policy, if set by the site, doesn&#39;t allow running browser scripts (which includes bookmarklets or extensions) on pages that don&#39;t allow loading scripts from other sources. Thankfully, Basecamp doesn&#39;t have this, but we saw this while testing with some other task-tracking systems, and I&#39;ve shared with Crossrider team the result of my investigation in their &lt;a href=&quot;https://getsatisfaction.com/crossrider/topics/appapi_ready_does_not_fire_on_select_pages_on_firefox#reply_14442480&quot;&gt;GetSatisfaction support system&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Chrome&lt;/b&gt;, thus, is our main development and distribution platform. The browser itself causes the least pain, everything is compatible, and submission to &lt;a href=&quot;https://chrome.google.com/webstore/detail/roadmap/ppcdhlicbeamihibghpgknfmonbhmnii&quot;&gt;Chrome Web Store&lt;/a&gt; works wonderfully.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhz0yKc1QpHZado3Fv2Z05D44tNtiprumdKKXcXR1wzzn00gXshAP9lPWOnoVT8Koz0pzCpQu1oNyJH_-3gF5myLJGDfYbA4Tu-7wwaJaKI-UCFcR-xiUlPFaJOwt24yE3pZOqnOs38zw/s1600/rm_web_store.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;291&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhz0yKc1QpHZado3Fv2Z05D44tNtiprumdKKXcXR1wzzn00gXshAP9lPWOnoVT8Koz0pzCpQu1oNyJH_-3gF5myLJGDfYbA4Tu-7wwaJaKI-UCFcR-xiUlPFaJOwt24yE3pZOqnOs38zw/s1600/rm_web_store.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Presentation often means attention.&lt;br /&gt;
Google tries hardest to “sell” our extension. &lt;br /&gt;
Apple doesn&#39;t even bother, and Mozilla doesn&#39;t allow us on their store. Sigh.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
The only issue that really bothers me is the recent ban on installing extension from sources other than the Web Store. There are “developer” ways to side-step it, so really not an issue, yet I am concerned about the direction that Chrome is heading — from openness to “caring about the users” by limiting them to least possible options.&lt;br /&gt;
&lt;br /&gt;
Which naturally brings us to &lt;b&gt;Safari&lt;/b&gt; :) The compatibility of extensions is good when it works, but you&#39;ll need to go through several gates of Apple hell before you even get there — running your extension in your browser on your computer requires a special developer certificate, developer tools are quite limited, and there are enough browser quirks to drive a mad person even madder. Best approach I found was to perform all development in Chrome, and then load the result in Safari, testing and debugging the Safari-specific issues.&lt;br /&gt;
&lt;br /&gt;
So while with a bit of sweat and pain, the extension does work on Safari, and we&#39;re happily featured in the &lt;a href=&quot;https://extensions.apple.com/details/?id=com.app57890-9QHUGJZ77G&quot;&gt;Safari Extensions Directory&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Did I forget anyone? Ah. Yes…&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Internet Explorer&lt;/b&gt;. Oh. Theoretically, the extension should work, and for simpler extensions it should be OK to test and claim IE support. In our case, though, it is an uphill battle to try to make it work. Since so few people use it, we decided to leave working out the “IE wrinkles” as lower priority, and then it turned out that the Internet Explorer extension runs in some limited JS context, that even some simplest JavaScript functions fail to run (e.g. .indexOf, .forEach etc). The error reporting is almost absent, too, so even debugging these issues means placing tons of console.log statements around the code, trying to guess where it fails now. On top of this, updating an extension once you change something in the code doesn&#39;t always work, sometimes requiring going to Control Panel / Add &amp;amp; Remove Programs, and even that is flaky.&lt;br /&gt;
&lt;br /&gt;
Don&#39;t get me wrong, otherwise I think that IE10 is a huge improvement on the previous versions, but its extension support looks to be an afterthought. May be Microsoft&#39;s “Spartan” effort will be better — we&#39;ll see.&lt;br /&gt;
&lt;br /&gt;
But for now we decided to support Firefox, Chrome and Safari. This covers an overwhelming majority of our user base.&lt;br /&gt;
&lt;h3&gt;
&lt;/h3&gt;
&lt;h3&gt;
Summary&lt;/h3&gt;
You can tell that I am pleased with this approach. Some development, especially debugging (especially on some browsers) can be fiddly, yet in general it feels great to know that almost any extension (within reason) can be developed using this approach — given time, perseverance and creativity :)&lt;br /&gt;
&lt;br /&gt;
And this is the main takeaway for me — I am glad that this project came about, and that I didn&#39;t try to wriggle out of it because “I don&#39;t know how to do it” and “This is outside of my expertise”. Turns out, I can do it, and I hope I&#39;ll have more new and interesting projects in the future.&lt;br /&gt;
&lt;br /&gt;
We die the day we stop learning.&lt;br /&gt;
&lt;br /&gt;
One thing that I especially wanted to highlight is Crossrider&#39;s wonderful support team. They can&#39;t always fix everything, some of the more significant issues were communicated to the development team and are still pending, yet they respond quickly, always pay the maximum attention to your request, are willing to check your code and suggest possible improvements, and left me impressed.&lt;br /&gt;
&lt;br /&gt;
No, I am no affiliated with them in any way. I just enjoyed working with their product and communicating with their staff.&lt;br /&gt;
&lt;br /&gt;
Makes me think that doing your job well and treating your customers with care means so much in our hectic world.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;Photo:&amp;nbsp;&lt;a href=&quot;https://www.flickr.com/photos/ensh/&quot;&gt;Emmanuel Huybrechts&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/7201374915700885702/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2015/03/developing-javascript-browser-extensions-with-crossrider.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/7201374915700885702'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/7201374915700885702'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2015/03/developing-javascript-browser-extensions-with-crossrider.html' title='Developing browser extensions using JavaScript with Crossrider framework'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaIlPnSvDp_cGIalIw0-27p8eFbHdDR16qd581HEG3XLjbFDslnYWoKu7I0aiXxjR2eU0pResih5jn1w_Hw6bXbgiMR3A6YHrzW6M9fiyXG8iKUkxN9HHkAIf7Eam0SX45hz42RA2I3Q/s72-c/cogs.jpg" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-6994613992454534850</id><published>2014-11-13T00:04:00.002+02:00</published><updated>2014-11-13T00:04:57.518+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="tools"/><category scheme="http://www.blogger.com/atom/ns#" term="ui"/><category scheme="http://www.blogger.com/atom/ns#" term="user experience"/><title type='text'>UX is about organization</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbfQBvBzsGfbE5LftxFjJBlqtqyvu1lMguqAiNiCVfKHuHZ_pEBX_wK-JQqMTIhZjDNXemH75b_wbYGnmyJ89py46V9kCJqLdxU3VSjD6uHIrc1cG-VqEZV6KWlMmvyEx5PRBY4Oj8ug/s1600/google-inbox.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbfQBvBzsGfbE5LftxFjJBlqtqyvu1lMguqAiNiCVfKHuHZ_pEBX_wK-JQqMTIhZjDNXemH75b_wbYGnmyJ89py46V9kCJqLdxU3VSjD6uHIrc1cG-VqEZV6KWlMmvyEx5PRBY4Oj8ug/s1600/google-inbox.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Google Inbox is certainly not complete.&lt;br /&gt;
&lt;br /&gt;
I miss being able to simply paste images from clipboard. I do want to have more text-formatting options (being especially fond of &quot;quotation&quot; formatting in any kind of software). Speaking of quotes, their detection in replies and forwards is still somewhat wonky in Inbox. And I am scared by a barren &quot;Settings&quot; screen — almost no tweaks or configs. What, Google is becoming like Apple? What a dreadful thought…&lt;br /&gt;
&lt;br /&gt;
But! I love what Google Inbox is, and, even if it makes some things less convenient, I am sticking to it, amazed at the fact that it just &quot;works&quot;.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
When I first read about it, and then watched not a very helpful demo, I assumed it would be akin to automatic &quot;Spam&quot; folder, just with more folder types. I was afraid it would &lt;i&gt;hide&lt;/i&gt; things from me, to make it &lt;i&gt;look&lt;/i&gt; simpler.&lt;br /&gt;
&lt;br /&gt;
And it certainly hid some settings, but that&#39;s not the point.&lt;br /&gt;
&lt;br /&gt;
I was concerned it would hide some emails. And, while I have a lot coming to my inbox — too much, in fact, — I can&#39;t allow a robot to decide what I see and what I don&#39;t see. This way I could miss something important, and with my job being a lot about communication — it could be disastrous.&lt;br /&gt;
&lt;br /&gt;
Instead of hiding, it &lt;i&gt;reorganizes&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Actually, it feels like somebody looked into my brain, how I use messages, and for different tasks I have different &lt;i&gt;contexts&lt;/i&gt;. It means that at any given time I don&#39;t need to see all of the messages in my inbox — I need to drill into groups, like &quot;Work&quot; or &quot;Family&quot;, and then I can respond to something immediately, and some other messages I think that I need to look at &quot;later tonight&quot;, or &quot;after the meeting on Thursday&quot;, and, until then, I don&#39;t need to see them anymore.&lt;br /&gt;
&lt;br /&gt;
And I just love the nice touch that messages aren&#39;t being &lt;i&gt;read&lt;/i&gt;, they&#39;re being &lt;i&gt;done&lt;/i&gt;. There&#39;s palpable satisfaction in pressing that green tick button to say that &quot;I&#39;ve dealt with it&quot;.&lt;br /&gt;
&lt;br /&gt;
So for me the lesson is that good UX approach doesn&#39;t mean simply hiding something. It means logically organizing visible data, so that I can quickly reach what I need — while not being distracted by what I don&#39;t need at the moment.&lt;br /&gt;
&lt;br /&gt;
I was afraid Inbox would take control out of my hands — yet it actually feels empowering. That&#39;s a buzz-word, I know.&lt;br /&gt;
&lt;br /&gt;
PS And yes, I&#39;d like to always see my &quot;Spam&quot; folder too. I don&#39;t trust a system to decide what to hide from me.&lt;br /&gt;
PPS While you&#39;re at it, please allow selecting all messages in &quot;Spam&quot;. Thanks ;)</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/6994613992454534850/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2014/11/ux-is-about-organization.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/6994613992454534850'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/6994613992454534850'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2014/11/ux-is-about-organization.html' title='UX is about organization'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbfQBvBzsGfbE5LftxFjJBlqtqyvu1lMguqAiNiCVfKHuHZ_pEBX_wK-JQqMTIhZjDNXemH75b_wbYGnmyJ89py46V9kCJqLdxU3VSjD6uHIrc1cG-VqEZV6KWlMmvyEx5PRBY4Oj8ug/s72-c/google-inbox.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-5110537742760927538</id><published>2014-09-05T01:47:00.000+03:00</published><updated>2014-09-05T01:52:32.017+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="crossrider"/><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="micro-solution"/><title type='text'>Micro-solution: Preserving input values against all odds (JavaScript)</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfPgjp-8c2xK-c8Pcd4ZX1Ssu8pL7bOY1scvTauxgu4vxNVarW11idmb8lKLv4Eam06qnGMK61Tlk6cxjAtn87wJoaqiHcPWlVO3IUg49u2MB-GaxDUKxuDTEFRuXXDLClLU7kv9ZRgw/s1600/preserve-your-valuables.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfPgjp-8c2xK-c8Pcd4ZX1Ssu8pL7bOY1scvTauxgu4vxNVarW11idmb8lKLv4Eam06qnGMK61Tlk6cxjAtn87wJoaqiHcPWlVO3IUg49u2MB-GaxDUKxuDTEFRuXXDLClLU7kv9ZRgw/s1600/preserve-your-valuables.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
The problem: How do you keep the already entered values of HTML inputs if you can&#39;t control when the containing document is closed or reopened?&lt;br /&gt;
&lt;br /&gt;
In my case, I am developing a browser extension which requires a configuration popup with some input fields. The user is expected to enter several values into the fields and there is a specific “Save” action, which performs an authentication check etc. I can process button presses etc — yet the popup itself (with all of its HTML, CSS and JavaScript) may be brutally closed by the browser without any prior notifications.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
For example, if the user clicks outside of this popup on the browser toolbar — bang! — the popup is dead. Our favourite user then re-opens the popup — and all the data they lovingly typed in — gone.&lt;br /&gt;
&lt;br /&gt;
So I need a simple method to store and repopulate input fields without any additional user action.&lt;br /&gt;
&lt;h3&gt;
Solution&lt;/h3&gt;
Start with the code:&lt;br /&gt;
&lt;pre style=&quot;background: #000000; color: #d1d1d1;&quot;&gt;&lt;span style=&quot;color: #9999a9;&quot;&gt;// Preserve real-time inputs data in case popup is closed externally&lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;// Set input event monitoring&lt;/span&gt;
$&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;input&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;on&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;input&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
 &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; popInputs &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; appAPI&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;db&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;get&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;popup_inputs&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;||&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
  
 popInputs&lt;span style=&quot;color: #d2cd86;&quot;&gt;[&lt;/span&gt;$&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;attr&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;id&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; $&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;val&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
 
 &lt;span style=&quot;color: #9999a9;&quot;&gt;// Using Crossrider local DB - could be localStorage&lt;/span&gt;
 appAPI&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;db&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;set&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;popup_inputs&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; popInputs&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;

&lt;span style=&quot;color: #9999a9;&quot;&gt;// Populate the inputs with pre-stored values&lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;// Retrieve the stored values from whatever you saved them to&lt;/span&gt;
&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; storedInputs &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; appAPI&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;db&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;get&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;popup_inputs&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
 
&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;storedInputs&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
 Object&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;keys&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;storedInputs&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;forEach&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;prop&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
  &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;storedInputs&lt;span style=&quot;color: #d2cd86;&quot;&gt;[&lt;/span&gt;prop&lt;span style=&quot;color: #d2cd86;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;
   $&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;#&#39;&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; prop&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;val&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;storedInputs&lt;span style=&quot;color: #d2cd86;&quot;&gt;[&lt;/span&gt;prop&lt;span style=&quot;color: #d2cd86;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
 &lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
The answer consists of two parts.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;First&lt;/b&gt;, we set watch for “input” events on our input controls (you may want to narrow it down with IDs and classes, I have no such need since I only have three inputs). Surprisingly, this works for every button stroke, and even for pasting text into the fields.&lt;br /&gt;
&lt;br /&gt;
This the current value of the field is then saved in your preferred storage, as part of an “popup_inputs” object, that just contains input values for each element ID. Nice and simple.&lt;br /&gt;
&lt;br /&gt;
Note that I am using this in &lt;a href=&quot;https://crossrider.com/&quot;&gt;Crossrider API&lt;/a&gt; context (it is a nice framework for creating browser extensions), so for convenience I use their local storage. You may use browsers localStorage instead, or whatever means you prefer.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Second&lt;/b&gt;, when our form is rendered, I check for presence of stored input values, and, enumerating the stored object&#39;s own properties (Object.keys(your_object) is really handy for this!), populate the inputs with their values — our property names are input IDs, so they&#39;re really easy to find now.&lt;br /&gt;
&lt;br /&gt;
And. It. Works.&lt;br /&gt;
&lt;br /&gt;
I&#39;ll appreciate any feedback and comments.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;Photo by &lt;a href=&quot;https://www.flickr.com/photos/ejchang/&quot;&gt;Eunice&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/5110537742760927538/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2014/09/preserving-html-input-values-javascript.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/5110537742760927538'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/5110537742760927538'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2014/09/preserving-html-input-values-javascript.html' title='Micro-solution: Preserving input values against all odds (JavaScript)'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfPgjp-8c2xK-c8Pcd4ZX1Ssu8pL7bOY1scvTauxgu4vxNVarW11idmb8lKLv4Eam06qnGMK61Tlk6cxjAtn87wJoaqiHcPWlVO3IUg49u2MB-GaxDUKxuDTEFRuXXDLClLU7kv9ZRgw/s72-c/preserve-your-valuables.jpg" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-3265455660556477010</id><published>2014-02-21T14:13:00.002+02:00</published><updated>2014-02-21T14:13:20.667+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="css"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="leadership"/><category scheme="http://www.blogger.com/atom/ns#" term="motivation"/><category scheme="http://www.blogger.com/atom/ns#" term="reading digest"/><title type='text'>Reading digest 04</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfXTIm2ko9yuktOgoN8hamLoMnfPJDdxQCsI8vTSFajH37coG-bM3KL3TWKCCAgaPU72LqBF479HFoLbLKy0a0uCazlg_A6SNxvty3fcdTSyXbaRmC5Nsx92-UwiiWBrkT58n_urUK8A/s1600/reading_digest_04.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfXTIm2ko9yuktOgoN8hamLoMnfPJDdxQCsI8vTSFajH37coG-bM3KL3TWKCCAgaPU72LqBF479HFoLbLKy0a0uCazlg_A6SNxvty3fcdTSyXbaRmC5Nsx92-UwiiWBrkT58n_urUK8A/s1600/reading_digest_04.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Not an easy time to for my country and for me, hard to watch the unfolding events and do something else — yet I am looking forward to a better future (what is man without hope?), and thus continue to learn and grow, as a human being and as a professional too.&lt;br /&gt;
&lt;br /&gt;
Also, I would have many more cool links to share if I held off any longer, don&#39;t want to War-and-Peace you, my dearest reader.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Developing&lt;/h3&gt;
&lt;a href=&quot;http://www.sitepoint.com/current-generation-css3-selectors/&quot; rel=&quot;nofollow&quot;&gt;The Current Generation of CSS3 Selectors&lt;/a&gt; — a good reminder of some potentially useful things. For example, I completely forgot about first-/last-/nth-of-type, and these could come in handy one day.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://flippinawesome.org/2013/12/23/45-useful-javascript-tips-tricks-and-best-practices/&quot; rel=&quot;nofollow&quot;&gt;45 Useful JavaScript Tips, Tricks and Best Practices&lt;/a&gt;&amp;nbsp;— even if you quickly scroll through it, I am quite sure you&#39;ll find something you didn&#39;t know — or knew and forgot. Nice and concise collection, not too verbose, so easy to quickly scroll through :)&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Thinking&lt;/h3&gt;
&lt;a href=&quot;http://www.labnol.org/software/find-right-chart-type-for-your-data/&quot; rel=&quot;nofollow&quot;&gt;Choose the Right Chart Type for your Data&lt;/a&gt;&amp;nbsp;— a “thought starter”, now that&#39;s a good approach! You may not agree with some of the choices, but — ha, that made you think, didn&#39;t it? So the thought-starter did its job! Also, it doesn&#39;t have &lt;a href=&quot;https://developers.google.com/chart/interactive/docs/gallery/sankey&quot; rel=&quot;nofollow&quot;&gt;Sankey diagrams&lt;/a&gt;, so may be you don&#39;t see some other cool — even if not very useful, — chart types? Let me know, I like this topic.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://arstechnica.com/gadgets/2014/02/the-2014-google-tracker-everything-we-know-google-is-working-on-this-year/&quot; rel=&quot;nofollow&quot;&gt;Everything we know Google is working on in 2014&lt;/a&gt;&amp;nbsp;— some stuff is cool, some is mundane, but Google in general is becoming scarier and scarier…&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://mercury.io/blog/the-psychology-of-waiting-loading-animations-and-facebook&quot; rel=&quot;nofollow&quot;&gt;The Psychology of Waiting, Loading Animations, and Facebook&lt;/a&gt;&amp;nbsp;— Houston airport extends walking distance to baggage claim by 500% — now that explains a lot of airports&#39; I&#39;ve seen! Back to the topic — the observation about custom vs stock waiting animation is also a neat one, even if not entirely credible it still makes sense.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.nngroup.com/articles/reciprocity-principle/&quot; rel=&quot;nofollow&quot;&gt;The Reciprocity Principle: Give Before You Take in Web Design&lt;/a&gt;&amp;nbsp;— love the idea that you need to provide value, show care, before expecting a return from your visitor. This correlates greatly with the Golden Rule of the Bible — “So in everything, do to others what you would have them do to you” (Mattew 7:12a), great to see that our society and good work depends on following such timeless principles&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Motivating&lt;/h3&gt;
&lt;a href=&quot;https://medium.com/think-different-think-stupid/c6ce326612c8&quot; rel=&quot;nofollow&quot;&gt;Something small, every day&lt;/a&gt; — &amp;nbsp;I can testify how much small but steady steps can make, and it is indeed easy to find this time. The hard part is faithfully keeping at it.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://37signals.com/&quot; rel=&quot;nofollow&quot;&gt;Two big announcements (by 37 Signals)&lt;/a&gt;&amp;nbsp;— hey, I actually liked their name! The decision about focusing on one product is… controversial. On the one hand, focused teams and products are for the win. On the other hand, there is always the issue of “all eggs in one basket”. Yet post-factum of Basecamp&#39;s overwhelmping success this is probably not a concern to them. Still, they had a cool name, shame about that.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://medium.com/book-digests/81b05b4715c6&quot; rel=&quot;nofollow&quot;&gt;10 Things Nobody Told You About Being Creative&lt;/a&gt; — «A work of art represents a struggle against limitations!» — love this! Despite a markety title (10 things? &lt;i&gt;Nobody&lt;/i&gt; told me? Rrrrright) — good and ponder-some points. Keep scrolling after the final photo, for some more tidbits of advice.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.designfaves.com/2014/02/simple-street-art-personifies-inanimate-objects&quot; rel=&quot;nofollow&quot;&gt;Simple street art personifies inanimate objects&lt;/a&gt; — to this I say, always try to find a way to bring joy to what you do, and to people who surround you!&lt;br /&gt;
&lt;br /&gt;
With that in mind — take care.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/3265455660556477010/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2014/02/reading-digest-04.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/3265455660556477010'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/3265455660556477010'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2014/02/reading-digest-04.html' title='Reading digest 04'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfXTIm2ko9yuktOgoN8hamLoMnfPJDdxQCsI8vTSFajH37coG-bM3KL3TWKCCAgaPU72LqBF479HFoLbLKy0a0uCazlg_A6SNxvty3fcdTSyXbaRmC5Nsx92-UwiiWBrkT58n_urUK8A/s72-c/reading_digest_04.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-3383735184044934881</id><published>2014-02-18T12:14:00.001+02:00</published><updated>2014-02-18T12:18:16.513+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="communication"/><category scheme="http://www.blogger.com/atom/ns#" term="leadership"/><category scheme="http://www.blogger.com/atom/ns#" term="management"/><title type='text'>Propaganda versus Glasnost</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;h2 class=&quot;intro&quot;&gt;
Issues arise in any sizable project. Devil hides in the details, and no plan can take them all into account. If you are managing such a train on fire, do you pretend that everything is great? Or…&lt;/h2&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8typaXXl8CSadVFIoEFVGpJGENHNX_TNwRyrggwFt5dj4Iscnl3MtEVG-Ozup2sJ8nIcqZ9umXAang7VbWNL2rVdZAAmfMiZnhBtHunC4WazicKc_D90J_bZaQ1uieM6tSCVIasCJnQ/s1600/propaganda-vs-pragmatism.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8typaXXl8CSadVFIoEFVGpJGENHNX_TNwRyrggwFt5dj4Iscnl3MtEVG-Ozup2sJ8nIcqZ9umXAang7VbWNL2rVdZAAmfMiZnhBtHunC4WazicKc_D90J_bZaQ1uieM6tSCVIasCJnQ/s1600/propaganda-vs-pragmatism.jpg&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Photo by&amp;nbsp;&lt;a href=&quot;http://www.flickr.com/photos/41626461@N06/&quot; rel=&quot;nofollow&quot;&gt;Dmitry Komarovsky&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;Actually, keeping a good and constructive attitude is a useful technique. “Don&#39;t panic!” is an excellent advice for any traveler from A to B, not just interstellar hitchhiker. If you allow the weight of all the issues, problems, risks, known and (worse!) unknown, to “get to you”, it could stop you from doing your job effectively, it could get conveyed to your team, and thus make matters only worse.&lt;br /&gt;
&lt;br /&gt;
Panic doesn&#39;t help.&lt;br /&gt;
&lt;br /&gt;
But! Does it mean you need to pretend everything is dandy, when in fact it is not?&lt;br /&gt;
&lt;br /&gt;
I&#39;ve grown in a culture, first USSR then its heavy legacy, which encourages superficial grand successes, huge monuments, grandiose architecture, massive choreographed events for display of power — surrounded by poverty and broken economics. Showing off at the cost of… well, everything. This year&#39;s Sochi games, a “feast in time of plague”, is an obvious illustration of this approach, yet it is happening on many many levels in our culture.&lt;br /&gt;
&lt;br /&gt;
In project management this means working on how you look, instead of on the project. You either postpone acknowledging the issues until it is inevitable (and then find anyone, anything, that you can blame, since even mentioning the fact of issues damages your image of a perfect leader), — or you work on solving the issues, which sometimes means involving the customer, losing your face a little, hearing unkind responses — but pushing forward to get the job done.&lt;br /&gt;
&lt;br /&gt;
The arguments in favour of a superficial approach are simple:&lt;br /&gt;
&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;The customer may not trust us in the future if they see that we were struggling.&lt;/li&gt;
&lt;li&gt;The competition should not be aware of our weakness, or they&#39;ll pounce.&lt;/li&gt;
&lt;li&gt;Everyone should think we never err, this will bring us more customers.&lt;/li&gt;
&lt;li&gt;(the final blow) Encountering issues is unprofessional.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
This is ridiculous. Ensuring that you look great at the cost of the service you are providing is as far from being “professional” as possible. And, when dealing with a pragmatic customer (not one who is also interested in just the surface success), they will understand that issues happen, so if we pretend that we are perfect — we look as simple liars. What a pragmatic customer needs to know if how do you plan to address issues that may happen, how you deal with the issues that did happen, and how you learn on the mistakes you&#39;ve made.&lt;br /&gt;
&lt;br /&gt;
Gorbachev was arguably forced to accept the “Glasnost” policy, yet this was the only way to start addressing the issues that have been accumulating for decades. Either that, or starve to death, North Korea-style. Many unwisely blame Gorbachev for “creating the issues”, though there is a huge difference between “creating” and “uncovering with the aim to solve”.&lt;br /&gt;
&lt;br /&gt;
If you do spot a customer who only needs a pretense success — run. In our locale this happens in government budget projects (almost guaranteed, in fact). In your case it may differ. Yet working on a project which emphasises form over substance, shining reports for a job poorly done, destroys you. Don&#39;t do it.&lt;br /&gt;
&lt;br /&gt;
On the other hand — be diplomatic about risks and issues. Don&#39;t scare the customers off, don&#39;t panic yourself, but get your act together, face the obstacle — and deal with it. If you fail — learn from the experience, and be better prepared next time.&lt;br /&gt;
&lt;br /&gt;
Or worry about how grand your mausoleum is going to be. Your choice.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/3383735184044934881/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2014/02/propaganda-versus-glasnost.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/3383735184044934881'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/3383735184044934881'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2014/02/propaganda-versus-glasnost.html' title='Propaganda versus Glasnost'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8typaXXl8CSadVFIoEFVGpJGENHNX_TNwRyrggwFt5dj4Iscnl3MtEVG-Ozup2sJ8nIcqZ9umXAang7VbWNL2rVdZAAmfMiZnhBtHunC4WazicKc_D90J_bZaQ1uieM6tSCVIasCJnQ/s72-c/propaganda-vs-pragmatism.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-801020836201730298</id><published>2014-02-06T14:30:00.000+02:00</published><updated>2014-02-06T14:30:16.955+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="reading digest"/><title type='text'>Reading Digest 03</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Fun fact — did you know that dialing “03” in USSR would allow you to call an ambulance? Anyway, here are some hand picks from what I read recently.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_q6u4i06SVObZos67iN3AqmAaSZtRM6dqljgyCfg_S6w4fZulHbbj_g503nsI962DNFdCKT7ND44Ri3WAyCrP9h9maUl5MVYqz-AR7A-9s4xZ-Qlf-kzFLKrRZxEy3kEqUcBH231ciA/s1600/reading_digest_03.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_q6u4i06SVObZos67iN3AqmAaSZtRM6dqljgyCfg_S6w4fZulHbbj_g503nsI962DNFdCKT7ND44Ri3WAyCrP9h9maUl5MVYqz-AR7A-9s4xZ-Qlf-kzFLKrRZxEy3kEqUcBH231ciA/s1600/reading_digest_03.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
The Work&lt;/h3&gt;
&lt;a href=&quot;http://thecodebarbarian.wordpress.com/2013/04/29/easy-web-prototyping-with-mongodb-and-nodejs/&quot; rel=&quot;nofollow&quot;&gt;The MEAN Stack: MongoDB, ExpressJS, AngularJS, and Node.js&lt;/a&gt; — I&#39;ve been looking at this one from a distance (the distance I typically call a “lack of time”), yet the ability to use JavaScript on all levels looks very attractive, at least for quick prototype building or solo-projects (along with all the Grunts and Gulps it brings along). Gotta try it out myself!&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://ux.stackexchange.com/a/18268&quot; rel=&quot;nofollow&quot;&gt;Why are there three default worksheets in MS Excel&lt;/a&gt; — don&#39;t you love it when the top answer starts with “I was on the Excel team when this was designed…”, history in the making! Quite a good answer, too, teaches you a thing or too about working with legacy software and an existing user base.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://blog.jquery.com/2014/01/24/jquery-1-11-and-2-1-released/&quot; rel=&quot;nofollow&quot;&gt;jQuery 1.11 and 2.1 Released&lt;/a&gt; — for me the interesting part is their work with npm and Bower — more community awareness, I suppose? No library is an island unto itself, yay!&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.ostraining.com/blog/marketing/7-lessons-writer-tweeting/&quot; rel=&quot;nofollow&quot;&gt;7 Lessons a Writer Learned from Tweeting&lt;/a&gt; — while the list itself is a bit too obvious, I totally agree on welcoming limitations in creativity — we&#39;re forced to think, choose carefully, edit-edit-edit, and make sure every word counts. Which also brings me to this:&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://theartreferences.tumblr.com/post/75285787187/cooperhelps-5-ways-to-write-a-damn-good&quot; rel=&quot;nofollow&quot;&gt;5 Ways to Write a (Very) Good Sentence&lt;/a&gt; — nice analysis of building bricks for powerful writing (and them bricks are not just “words”, nay).&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
The Fun (at work)&lt;/h3&gt;
&lt;a href=&quot;http://www.designfaves.com/2014/01/11-comparative-maps-create-surprising-size-perspectives&quot; rel=&quot;nofollow&quot;&gt;Comparative maps create surprising size perspectives&lt;/a&gt; — some enlightening information to be sure, yet also makes you think about how far you&#39;d want to go to visualize data. Also — Monaco!&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://color.method.ac/&quot; rel=&quot;nofollow&quot;&gt;Color Matching Game&lt;/a&gt; — a bit too hectic for me, but a nice visual tool-lite to teach a “feel” for color. Make sure to check their &lt;a href=&quot;http://method.ac/&quot; rel=&quot;nofollow&quot;&gt;other games&lt;/a&gt; too, I find that a lot of homegrown designers have no clue as to the basics (kerning, whaa?), and this could be a good start.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
The Conclusion&lt;/h3&gt;
I like observing solutions that people come up with, especially talented people in very limiting situations. So, may we all learn to be as efficient in our work and live, as these&amp;nbsp;&lt;a href=&quot;http://www.youtube.com/watch?v=4JeNbmoJB6Q&amp;amp;feature=player_embedded&quot; rel=&quot;nofollow&quot;&gt;firefighting planes that refuel on the go&lt;/a&gt;. Can you imagine what it&#39;d be like? If you can — do it! :)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/801020836201730298/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2014/02/reading-digest-03.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/801020836201730298'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/801020836201730298'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2014/02/reading-digest-03.html' title='Reading Digest 03'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_q6u4i06SVObZos67iN3AqmAaSZtRM6dqljgyCfg_S6w4fZulHbbj_g503nsI962DNFdCKT7ND44Ri3WAyCrP9h9maUl5MVYqz-AR7A-9s4xZ-Qlf-kzFLKrRZxEy3kEqUcBH231ciA/s72-c/reading_digest_03.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-1980335729693784851</id><published>2014-02-04T14:54:00.004+02:00</published><updated>2014-02-04T14:54:37.118+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="management"/><category scheme="http://www.blogger.com/atom/ns#" term="tools"/><title type='text'>You need to step away from your computer. Probably now.</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
If you are a developer, designer, writer, editor, or any sort of person who gets so absorbed in your work that you can start in the morning and then be shocked by the time on your watch when you reluctantly force yourself to stop in the evening — then you probably need someone to remind you to take breaks from your engrossing and exciting creative work (which is a great problem to have, to be honest).&lt;br /&gt;
&lt;br /&gt;
You need this:&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcZ_Qmfk7G1LNYrXlFKm7tN6t2fGhkssV1tBMS7PAPO__w1-JyXq0F12swV3px5HzmyWf-CP-txwvbJiVhbMR0TBFI6orXUFy4EX-RJK4T9yFofpdHuzCyM_M0J9XS75whbh9iZGljpw/s1600/rest_break_nature.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcZ_Qmfk7G1LNYrXlFKm7tN6t2fGhkssV1tBMS7PAPO__w1-JyXq0F12swV3px5HzmyWf-CP-txwvbJiVhbMR0TBFI6orXUFy4EX-RJK4T9yFofpdHuzCyM_M0J9XS75whbh9iZGljpw/s1600/rest_break_nature.jpg&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;b&gt;Yes, this.&lt;/b&gt;&lt;br /&gt;(photo by &lt;a href=&quot;http://www.flickr.com/photos/avatar_lv/&quot; rel=&quot;nofollow&quot;&gt;Andris&lt;/a&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
…yet keep forgetting about it. So I&#39;ll share a small gem of a tool I am using for this (on Windows) — &lt;a href=&quot;http://www.workrave.org/&quot;&gt;WorkRave&lt;/a&gt;.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
It is a small tool that sits in your tray, with a possibility to show a tiny countdown panel, which will remind you to take your prescribed break at preset intervals of time. You can use this time to relax your eyes, stretch your legs, take a walk to get another cup of tea or (even better!) pure water, breathe some fresh air* and smell the roses. Unless you&#39;re allergic to those.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;* — smokers, as I understand, don&#39;t need an external reminder, yet I would hardly call such breaks healthy.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
You can configure micro-breaks (to close your eyes for a second, I suppose), rest breaks, and a daily limit. I only use rest breaks, here&#39;s the configuration (5 minutes every 45 minutes):&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuqbKC93omfVdEdNxV6IUsGgYluZ9447KJq8pzBHCEuYuEqXpa72c6jtaleZxWISjsQQl5iNlxVDp1WA0MvKyVjW1S4mMvpMn3USksn9VuIU-9WfX6ZpxCicPo97bI5raIzqUPxzUu5w/s1600/workrave_config.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuqbKC93omfVdEdNxV6IUsGgYluZ9447KJq8pzBHCEuYuEqXpa72c6jtaleZxWISjsQQl5iNlxVDp1WA0MvKyVjW1S4mMvpMn3USksn9VuIU-9WfX6ZpxCicPo97bI5raIzqUPxzUu5w/s1600/workrave_config.png&quot; height=&quot;325&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
I wouldn&#39;t call WorkRave unobtrusive, yet that is the idea, isn&#39;t it? When the time comes for your configured rest break — you will get a floating pop up which will allow you to lock the PC, skip the break (sometimes you have to), or postpone the break:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCggH75cKaze3YWaufYhy1CiRw1JOuoNEL-e5Lc466JliLXHTDJ16L_ja2iSFCpm5DckGhtw0b-ICv9As9TRbtdk4VgkU2suTy6fPL60jxgvg-Sl_MQLxd_UryfAAoBPfBi6gePdfrBw/s1600/workrave_rest_break.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCggH75cKaze3YWaufYhy1CiRw1JOuoNEL-e5Lc466JliLXHTDJ16L_ja2iSFCpm5DckGhtw0b-ICv9As9TRbtdk4VgkU2suTy6fPL60jxgvg-Sl_MQLxd_UryfAAoBPfBi6gePdfrBw/s1600/workrave_rest_break.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
The tool also tracks periods of inactivity (i.e. lack of keyboard / mouse input — it cannot see your deeply thoughtful face when you do nothing), and doesn&#39;t ask you to take a break after you just got back from a long meeting away from the desk.&lt;br /&gt;
&lt;br /&gt;
I recommend this to colleagues too — doing the same thing for too long causes issues for productivity, and sometimes stepping away for a couple of minutes may help your brain (i.e. — you) solve a problem that you could not crack open for hours.&lt;br /&gt;
&lt;br /&gt;
You can download it &lt;a href=&quot;http://www.workrave.org/download/&quot; rel=&quot;nofollow&quot;&gt;here&lt;/a&gt;. It even shows a Linus version, yet I didn&#39;t try it.&lt;br /&gt;
&lt;br /&gt;
My main issue, and it has nothing to do with the software, is that I “postpone” way too often — looks like I have a cool job after all! :) Otherwise, it helps me take much needed breaks and thus keep my health, my eyesight and my sanity (however relative) in check.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/1980335729693784851/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2014/02/you-need-to-step-away-from-your.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/1980335729693784851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/1980335729693784851'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2014/02/you-need-to-step-away-from-your.html' title='You need to step away from your computer. Probably now.'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcZ_Qmfk7G1LNYrXlFKm7tN6t2fGhkssV1tBMS7PAPO__w1-JyXq0F12swV3px5HzmyWf-CP-txwvbJiVhbMR0TBFI6orXUFy4EX-RJK4T9yFofpdHuzCyM_M0J9XS75whbh9iZGljpw/s72-c/rest_break_nature.jpg" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-5750009742326912293</id><published>2014-01-29T17:42:00.000+02:00</published><updated>2014-01-29T17:46:02.803+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="design"/><category scheme="http://www.blogger.com/atom/ns#" term="logo"/><category scheme="http://www.blogger.com/atom/ns#" term="tools"/><title type='text'>Designing a logo for Friday.Night youth events</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Recently I designed a logo for &lt;a href=&quot;http://vk.com/frivnings&quot;&gt;Friday.Night&lt;/a&gt; events («Пятница. Вечер» — in Russian) held by&amp;nbsp;&lt;a href=&quot;http://aomegaonline.org/&quot;&gt;“Alpha and Omega” Christian Youth Society&lt;/a&gt;. I had to do it rather quickly, yet I quite enjoyed both the result and the process (which is precious, won&#39;t you agree?). Below I&#39;ll share the thinking and the approach I took in this.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNp5aCWetS5pkHU047PSabHj2Zprx9Z6xbYv_f7_vcQDt5sfGbe6OIR-hMsyJMsNe3ps_xeARLw2pQf8VdTvfZXieemG4w4ujvmHbr7K-SNUt2RHyFX_zvdfPlAeHXMUhhWwnOc0HDeQ/s1600/friday_night_logo.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNp5aCWetS5pkHU047PSabHj2Zprx9Z6xbYv_f7_vcQDt5sfGbe6OIR-hMsyJMsNe3ps_xeARLw2pQf8VdTvfZXieemG4w4ujvmHbr7K-SNUt2RHyFX_zvdfPlAeHXMUhhWwnOc0HDeQ/s1600/friday_night_logo.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;
The Task&lt;/h3&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
Friday.Night events are weekly meetings for Christian youth to enjoy their time together and be able to invite their unbelieving friends to. Each Friday the meetings could have a different theme and format (e.g. we had an Acoustic Music concert, a “Mafia” game night, a New Years Masquerade and cooking evenings dedicated to sushi, and then pirogi). Yet the common characteristic of these evenings is that they are friendly and fun, with the goal of welcoming new people in for them to get to know Christians better and not be afraid to come to a Sunday gathering.&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
The Idea&lt;/h3&gt;
I have to admit that I took a very straightforward route here, yet it may not be obvious on the first glance. The rectangles represent the week (in our culture it starts on Monday), with different random “things to do” on each one, yet two of them stand out. Friday, obviously, is the big one, since it is the focus of the logo. If shows the Sun setting, and stars are starting to shine — because, you know, “night”. The second important day is Sunday, since these are Christian events, so the last rectangle signifies a church, with the burgundy colour and welcoming doors — instead of windows of the other “buildings”.&lt;br /&gt;
&lt;br /&gt;
The Sunday colour is then consciously repeated in the capital letters and in the “dot”, for balance and unity.&lt;br /&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
So that&#39;s that. I hoped to introduce the fun / youthful factor by playing with the typography, and achieved it to some extent, yet I believe it still looks a tad too formal. I guess it comes from my experience, where I almost always work on logos / designs for serious things. I need to improve my “crazy” skills, then :)&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
The Process&lt;/h3&gt;
This was created in &lt;a href=&quot;http://inkscape.org/en/&quot;&gt;Inkscape&lt;/a&gt;, a freeware vector editing software. I don&#39;t know how it compares to Adobe Illustrator since I never used it, yet I&#39;ve found Inkscape to be good for my needs — even if it is a bit awkward and rough around the edges, it is still a powerful tool.&lt;br /&gt;
&lt;br /&gt;
For the text, each letter was created as a separate “text” object, since I wanted maximum freedom in sizing and position — since that would be the main vehicle for expressing the “fun” effect, while also I needed to balance them carefully (and I believe this could still be improved). Highlights are additional freehand vector shapes, roughly directed towards the setting Sun:&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi00EaCZE0YT8ZHDnMVLWX1yFTpNsCcgMQKgtscngPNF2d6qh9pZzZ95i-qmnihhdd8cjx1oTWR6pA3zoLR8AJTbQyareDLOW8WnCbFlYcQZhBPPQKJcy5gzTrp77AYVGxPBmKxQHxE_Q/s1600/friday_night_process_type.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi00EaCZE0YT8ZHDnMVLWX1yFTpNsCcgMQKgtscngPNF2d6qh9pZzZ95i-qmnihhdd8cjx1oTWR6pA3zoLR8AJTbQyareDLOW8WnCbFlYcQZhBPPQKJcy5gzTrp77AYVGxPBmKxQHxE_Q/s1600/friday_night_process_type.jpg&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;Highlights proved to be a great asset to the “feel” of the logo, with them it looks… well, polished.&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
I&#39;ve made several attempts at conveying the “Night” idea in the Friday rectangle. I browsed through a ton of samples on &lt;a href=&quot;http://logopond.com/&quot; rel=&quot;&quot;&gt;LogoPond&lt;/a&gt; for ideas and inspiration, though I made sure not to directly copy anything I saw.&lt;br /&gt;
&lt;br /&gt;
A lot of vector shapes are used, as well as an overlay of gradient glow, to prevent a sterile mechanical feel (half-successfully):&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIfI_4UB_5jnGI5wqAkseQ2HfOZV9cHdVkeGJDXkdGcmegsslGMremIIxAZy3c1THNSUZkSdzwc56S4pXb4AnRkDf7_hdiz63tTKuzqkYQvvBS7YNTbMXeso4xDBcqURxI24OuoKPQNQ/s1600/friday_night_process_graphic.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIfI_4UB_5jnGI5wqAkseQ2HfOZV9cHdVkeGJDXkdGcmegsslGMremIIxAZy3c1THNSUZkSdzwc56S4pXb4AnRkDf7_hdiz63tTKuzqkYQvvBS7YNTbMXeso4xDBcqURxI24OuoKPQNQ/s1600/friday_night_process_graphic.jpg&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;b&gt;A palm tree on Saturday is also a nice touch, /me thinks.&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
Since a lot of stray shapes and objects were involved, I worked in layers, to be able to select / copy / edit a certain part of the image without affecting the rest. Here&#39;s the list of layers I used:&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZmuC2rglJxppC1arWKaWN1GGxqQ4ZbZfCs1b4ks77sV-d3Izls1NCUWKu5P8yodvZkF0O7PIReZoLvUQoop72i2G9xJyYZh6pH04owzlKNJsp3mqLlL8wWEX8HpTkSsXC773rSljhaQ/s1600/friday_night_process_layers.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZmuC2rglJxppC1arWKaWN1GGxqQ4ZbZfCs1b4ks77sV-d3Izls1NCUWKu5P8yodvZkF0O7PIReZoLvUQoop72i2G9xJyYZh6pH04owzlKNJsp3mqLlL8wWEX8HpTkSsXC773rSljhaQ/s1600/friday_night_process_layers.jpg&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;b&gt;This also serves as a primitive&amp;nbsp;versioning structure, you can tell I had several goes at text placement.&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
For low-resolution usage I created a smaller version, which lacks any details in the buildings, has less highlights on the letters, and uses simplified “Night” graphic on the tallest building. This is necessary to avoid visual noise — though, to be honest, it may require further refinement if this logo gets used in such limiting contexts.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-VL8QLMdWdEPDysBJX0nRs6qFUzUiEmsoPf-yUm5TNIJRZaLTuuZXXVXYvgCQ2nLZRpDzUBew1cWmDUf9vmzFFY4-04IQOOe0-jk4_VnA96PBnamrpZnyClGGBQT2Zp6949HfSUqQKg/s1600/friday_night_logo_small.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-VL8QLMdWdEPDysBJX0nRs6qFUzUiEmsoPf-yUm5TNIJRZaLTuuZXXVXYvgCQ2nLZRpDzUBew1cWmDUf9vmzFFY4-04IQOOe0-jk4_VnA96PBnamrpZnyClGGBQT2Zp6949HfSUqQKg/s1600/friday_night_logo_small.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
I wouldn&#39;t be a proper creative if I were fully happy with this, yet I still like the look of it. The main downsides are that it should be less formal and strict, both in the graphic and the colouring, and the idea behind it is too down-to-business, I would like it to be less straight forward.&lt;br /&gt;
&lt;br /&gt;
Also, I can&#39;t shake the feeling that I&#39;ve seen it somewhere, yet can&#39;t nail it either. Nothing new under the Moon, eh?&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/5750009742326912293/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2014/01/designing-logo-for-fridaynight-youth.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/5750009742326912293'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/5750009742326912293'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2014/01/designing-logo-for-fridaynight-youth.html' title='Designing a logo for Friday.Night youth events'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNp5aCWetS5pkHU047PSabHj2Zprx9Z6xbYv_f7_vcQDt5sfGbe6OIR-hMsyJMsNe3ps_xeARLw2pQf8VdTvfZXieemG4w4ujvmHbr7K-SNUt2RHyFX_zvdfPlAeHXMUhhWwnOc0HDeQ/s72-c/friday_night_logo.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-4551358854648412680</id><published>2014-01-21T23:33:00.000+02:00</published><updated>2014-01-21T23:33:41.172+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="links"/><category scheme="http://www.blogger.com/atom/ns#" term="misc"/><category scheme="http://www.blogger.com/atom/ns#" term="tools"/><title type='text'>Do Not Read It Later!</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
If you&#39;re in IT, you probably read a lot. If you are on the Internet, you probably read a lot too (or look at pictures, which is like reading a thousand words… almost). And it happens in spells, doesn&#39;t it? You open an article, follow a link or two, check up a definition of a new term, a biography of a famous person, follow to a page of their quotes, then reading reviews of their books, then checking an article describing the nuances of backend architecture of the site you were reading the reviews on… and it continues, an endless fractal of spreading links, in space &lt;i&gt;and&lt;/i&gt; time.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNtxIZLGAuPgPMvtkbMjExVEtb5pfpCx1uSC_ym3_a6Lk2yzRv1ycmPSpQxyzBOHjmgVn88yFsM0hWXzclpSGs8rYTt3lOH_0iOmA4-CABb7JTC1_fr8X5K1pTFOpFE539GMDCAJ5OKg/s1600/dont-read-it-later.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNtxIZLGAuPgPMvtkbMjExVEtb5pfpCx1uSC_ym3_a6Lk2yzRv1ycmPSpQxyzBOHjmgVn88yFsM0hWXzclpSGs8rYTt3lOH_0iOmA4-CABb7JTC1_fr8X5K1pTFOpFE539GMDCAJ5OKg/s1600/dont-read-it-later.jpg&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;b&gt;You&#39;ll see what I&#39;m getting at.&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Then you end up with too much to read. A good problem to have, surely — you don&#39;t want to miss the useful information, yet you can&#39;t afford to spend so much time reading this very moment. So you postpone the reading. And there are services that help you do it — like the precisely named &lt;a href=&quot;http://getpocket.com/&quot; rel=&quot;nofollow&quot;&gt;Read It Later&lt;/a&gt; (now sadly re-christened as “Pocket”, thus losing all personality). There are other services of the kind, all nice and helpful.&lt;br /&gt;&lt;br /&gt;
My opinion and experience of this may be a very subjective one, your mileage may vary, yet my advice — don&#39;t. &lt;a href=&quot;http://www.youtube.com/watch?v=piVnArp9ZE0&quot; rel=&quot;nofollow&quot;&gt;It&#39;s a trap!&lt;/a&gt; (couldn&#39;t resist, sorry)&lt;br /&gt;
&lt;br /&gt;
For me these fire-and-forget backups simply turn into the same kind of storage where you put stuff to forget about it. Like your attic. Like your basement. Like that endless warehouse in the Raiders of the Lost Ark. David Allen was right when he said that putting things down in writing helps ease your mind. Putting things in RIL-type service you tell yourself “I&#39;ll read it”, yet you never* do.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;* — opening the service once a year to see hundreds of unread articles doesn&#39;t count. Sorry, no, it doesn&#39;t.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
So what do I recommend? Somewhat unrealistic, and doesn&#39;t reduce your stress level, yet I try to either read it immediately, just close it or keep it in an open tab in your browser.&lt;br /&gt;
&lt;br /&gt;
The reasoning:&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Read it immediately — obvious. You can skim it, you can diagonal-read it, if only to get the gist of it and be done with it. Problem solved.&lt;/li&gt;
&lt;li&gt;Close it — be decisive, for goodness sake! You thought it would be interesting, and it could be fun, yet you just don&#39;t have the time, and it isn&#39;t that useful after all, is it?&lt;/li&gt;
&lt;li&gt;Keep it in the open tab — so it annoys you. Yes! First it won&#39;t bother you much, then you&#39;ll have so many tabs that you won&#39;t be able to read their titles — that&#39;s when you will be gently nudged towards the decision to either read it (see above) or close it (see above).&lt;/li&gt;
&lt;/ul&gt;
Information ages. You move on (and age, too). Not everything you thought was useful at the time is actually useful even a couple of days later. Adding more stuff to the huge dump does not increase your chances of ever getting to the business of cleaning the dump out.&lt;br /&gt;
&lt;br /&gt;
Now, you may have a system, a recommendation, an approach to how you deal with this — and I&#39;d love to hear it. I may learn something interesting. And my open tabs annoy me :)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/4551358854648412680/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2014/01/do-not-read-it-later.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/4551358854648412680'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/4551358854648412680'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2014/01/do-not-read-it-later.html' title='Do Not Read It Later!'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNtxIZLGAuPgPMvtkbMjExVEtb5pfpCx1uSC_ym3_a6Lk2yzRv1ycmPSpQxyzBOHjmgVn88yFsM0hWXzclpSGs8rYTt3lOH_0iOmA4-CABb7JTC1_fr8X5K1pTFOpFE539GMDCAJ5OKg/s72-c/dont-read-it-later.jpg" height="72" width="72"/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-3277509295382289616</id><published>2014-01-17T13:47:00.001+02:00</published><updated>2014-01-17T16:52:59.235+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="design"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="management"/><category scheme="http://www.blogger.com/atom/ns#" term="reading digest"/><title type='text'>Reading Digest 02</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
So, I&#39;ve been reading (again, yes), and here are some links that I think your could find useful and interesting. Remember — keep studying, yet &lt;a href=&quot;http://www.amaslo.com/2012/08/study-study-learn.html&quot;&gt;strive to learn&lt;/a&gt;!&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-HGR1matPbVnK5s5LLNAcI9MUzLL4-9COIkzqpAKGfQt_Lq5bvhdvlMC2dQnRIDAbE7-IO-jvr5Mbliv3D2LjXgSMJ0t23LEQmVs45OffS19wl9oaTybz8sqKH3-2vOaaUTpq5tZKSQ/s1600/reading_digest_02.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-HGR1matPbVnK5s5LLNAcI9MUzLL4-9COIkzqpAKGfQt_Lq5bvhdvlMC2dQnRIDAbE7-IO-jvr5Mbliv3D2LjXgSMJ0t23LEQmVs45OffS19wl9oaTybz8sqKH3-2vOaaUTpq5tZKSQ/s1600/reading_digest_02.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
The Useful&lt;/h3&gt;
&lt;div&gt;
&lt;a href=&quot;http://24ways.org/2013/managing-a-mind/&quot;&gt;Managing a Mind&lt;/a&gt; — a very sincere and open confession with a way forward, how our virtual presence can cause a very real crisis in our psyche. Even though it is not a specific to-do list, still I find that being aware about such issues can be of huge practical use for us.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;a href=&quot;https://www.gov.uk/design-principles&quot;&gt;Gov.UK Design Principles&lt;/a&gt; — surprised to see a government agency take such a straight-forward no-BS approach. Good example for all of us. I especially like their VAT page screenshot, how they identified the single number most users will be looking for and just put it at the top, in huge font (the concept of “&lt;a href=&quot;http://en.wikipedia.org/wiki/Desire_path&quot;&gt;desire paths&lt;/a&gt;” is also mentioned, and it is a fun thought to look into)&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;a href=&quot;http://24ways.org/2013/javascript-taking-off-the-training-wheels/&quot;&gt;JavaScript: Taking off the training wheels&lt;/a&gt; — right, I am guilty of being somewhat un-learned in the deeper concepts of JavaScript, so this is a nice overview of what I or any person in a similar position might want to try next, to strengthen their footing.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://alistapart.com/about/style-guide&quot;&gt;ALA&#39;s style guide&lt;/a&gt; — what is it with me liking to read (at least skim over) style guides? I like to see a clear structure laid out, which should help anyone joining the team quickly get onboard. So this is a neat read, though looks like outdated (I couldn&#39;t find their article headings in H2, so there).&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
The Interesting&lt;/h3&gt;
&lt;div&gt;
&lt;a href=&quot;http://blogs.msdn.com/b/eric_brechner/archive/2013/12/01/the-flow-fallacy.aspx&quot;&gt;The flow fallacy&lt;/a&gt; — I don&#39;t fully agree with this, yet this is a nice and thoughtful alternative-angle look. Of course all developers want their rooms, don&#39;t want anyone to ever bother them, and… an ice-cream. Or two. Yet working in a team (or working for a customer) means that sometimes you have to step on your wounded introvercy and talk, listen, get interrupted — or even interrupt.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.dphrygian.com/wordpress/?p=104&quot;&gt;Eldritch: Mountains of Post-Mortem-ness&lt;/a&gt; — ah, game development, isn&#39;t that why we all picked up the job? Probably not, but still it is very interesting to read an overview of a moderately successful personal project. I really like how this guy approached the task — methodical, meticulous, careful. The financial overview is also enlightening, both the plan and the outcome.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://theartreferences.tumblr.com/post/71996201029/cvilbrandt-jamesab-x-x-by-devin&quot;&gt;Lots of visual colouring / rendering tutorials&lt;/a&gt;&amp;nbsp;—&amp;nbsp;good food for study, if you&#39;re into that kind of thing. Or just look at how illustrators approach the task nowadays.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://static.oculusvr.com/sdk-downloads/documents/OculusBestPractices.pdf&quot;&gt;Oculus VR Best Practices document&lt;/a&gt; — this is what Neo (Mr.Anderson) was afraid of, and what many of us are looking forward to. Some educating points on this document, about what is required for a good virtual reality experience.&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
The Inspiring&lt;/h3&gt;
&lt;a href=&quot;http://www.kickstarter.com/year/2013&quot;&gt;The Year 2013 In Kickstarter&lt;/a&gt; — not only a very well presented, yet also really inspiring to see how the online community comes together to “make things happen” (forgive me the shameless cliche). I am aware that Kickstarter is not all good and perfect, yet its highlights are excellent.&lt;br /&gt;
&lt;br /&gt;
With that in mind — let&#39;s make stuff happen! Take care :)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/3277509295382289616/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2014/01/reading-digest-02.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/3277509295382289616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/3277509295382289616'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2014/01/reading-digest-02.html' title='Reading Digest 02'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-HGR1matPbVnK5s5LLNAcI9MUzLL4-9COIkzqpAKGfQt_Lq5bvhdvlMC2dQnRIDAbE7-IO-jvr5Mbliv3D2LjXgSMJ0t23LEQmVs45OffS19wl9oaTybz8sqKH3-2vOaaUTpq5tZKSQ/s72-c/reading_digest_02.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-3047888376369319687</id><published>2014-01-14T12:22:00.002+02:00</published><updated>2014-01-14T14:25:02.677+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="html"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><title type='text'>Conditional Enter / Submit handling in HTML forms with JavaScript</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;h2 class=&quot;intro&quot; style=&quot;text-align: left;&quot;&gt;
The problem: if you press Enter key while inside a field of HTML form — the form will execute its submit action. Thus if your users are used to pressing return to move to the next field — they will be unpleasantly surprised. I&#39;ll show how this can be changed on example of a simple login form.&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/h2&gt;
This will be a quick one, since the task is rather straightforward.&lt;br /&gt;
&lt;br /&gt;
Let&#39;s assume a very simple HTML form structure:&lt;br /&gt;
&lt;pre style=&quot;background: #000000; color: #d1d1d1;&quot;&gt;&lt;span style=&quot;color: #ff8906;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color: #ff8906;&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #ff8906;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;input&lt;/span&gt; id&lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&quot;login&quot;&lt;/span&gt; name&lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&quot;login&quot;&lt;/span&gt; type&lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&quot;text&quot;&lt;/span&gt; placeholder&lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&quot;Your login&quot;&lt;/span&gt;&lt;span style=&quot;color: #ff8906;&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #ff8906;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;input&lt;/span&gt; id&lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&quot;password&quot;&lt;/span&gt; name&lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&quot;password&quot;&lt;/span&gt; type&lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&quot;password&quot;&lt;/span&gt; placeholder&lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&quot;Your password&quot;&lt;/span&gt;&lt;span style=&quot;color: #ff8906;&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #ff8906;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;button&lt;/span&gt; type&lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&quot;submit&quot;&lt;/span&gt; id&lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&quot;submit&quot;&lt;/span&gt;&lt;span style=&quot;color: #ff8906;&quot;&gt;&amp;gt;&lt;/span&gt;Submit&lt;span style=&quot;color: #ff8906;&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color: #ff8906;&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #ff8906;&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;form&lt;/span&gt;&lt;span style=&quot;color: #ff8906;&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
If you don&#39;t do anything about it, pressing Enter key while in the Login input field will invoke the Submit action. Not good.&lt;br /&gt;
&lt;br /&gt;
To demonstrate it I&#39;ll add an alert on submit action (using jQuery for readability in this case), this will help us see clearly when it is actually being invoked:&lt;br /&gt;
&lt;pre style=&quot;background: #000000; color: #d1d1d1;&quot;&gt;$&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;form&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;submit&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt; 
    alert&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;Submit!&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt; 
&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;
For this study let&#39;s concentrate on just the Login field. If you want to stop submit from being invoked on an empty Password field you can apply the same principle.&lt;br /&gt;
&lt;br /&gt;
The code:&lt;br /&gt;
&lt;pre style=&quot;background: #000000; color: #d1d1d1;&quot;&gt;$&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;#login&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;on&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;keydown&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;e&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
    &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;e&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;keyCode &lt;span style=&quot;color: #d2cd86;&quot;&gt;==&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;13&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
        &lt;span style=&quot;color: #9999a9;&quot;&gt;// Move to password field if login not empty&lt;/span&gt;
        &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;$&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;#login&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;val&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;!==&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;
            $&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;#password&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;focus&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
        
        &lt;span style=&quot;color: #9999a9;&quot;&gt;// Stop submit from being invoked&lt;/span&gt;
        e&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;preventDefault&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
    &lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;
&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
The following is happening above:&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;i&gt;keydown&lt;/i&gt; even is being overridden for the login field.&lt;/li&gt;
&lt;li&gt;In the event handler we check for key code 13, which corresponds to Enter key press.&lt;/li&gt;
&lt;li&gt;If the login field is not empty (&lt;i&gt;val()&lt;/i&gt; is not an empty string) — then move the cursor (with &lt;i&gt;.focus()&lt;/i&gt; method) to the password field.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;preventDefault()&lt;/i&gt; is called on the event to, er, prevent it from executing the default action. In our case, the default action on pressing Enter is to submit the form, so this action is being prevented. Just what we need!&lt;/li&gt;
&lt;/ul&gt;
Here&#39;s the corresponding &lt;a href=&quot;http://jsfiddle.net/NPC42/99w5g/&quot;&gt;demo fiddle&lt;/a&gt;. You can comment out the keydown event override to see how Submit is called without it.&lt;br /&gt;
&lt;br /&gt;
I hope this helps, and take care!&lt;br /&gt;
&lt;br /&gt;
PS I do need to spend some time getting away from reliance on jQuery — it is one of my (plenty) weaknesses. I plan to do some studying this week, yet it is so easy to demonstrate event handling etc using it, so I think I&#39;ll keep using it in my code examples, except for when pure JavaScript is easier to understand.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/3047888376369319687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2014/01/conditional-enter-submit-handling-in.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/3047888376369319687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/3047888376369319687'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2014/01/conditional-enter-submit-handling-in.html' title='Conditional Enter / Submit handling in HTML forms with JavaScript'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-5099878250429835337</id><published>2014-01-09T10:52:00.000+02:00</published><updated>2014-01-09T10:55:29.306+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="communication"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="links"/><category scheme="http://www.blogger.com/atom/ns#" term="misc"/><category scheme="http://www.blogger.com/atom/ns#" term="reading digest"/><category scheme="http://www.blogger.com/atom/ns#" term="tools"/><title type='text'>Reading digest 01</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Right, sometimes I&#39;d like to share some of the cool/useful/thoughtful things that I&#39;ve read/watched, so here goes. Note that this may look like an odd mix, but so are my interests :)&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4yowGdHG33ba_w7cy9lm42-adyRavLGJQZNfD01IANrXCLgDpx6SrucfXbZxpPLHIXzi9Hlut0QHAJaAfSKAdSE4zdxwFPm2zkoIyh-3qbVzFXTbV_MhXRBuul1s1A_Wt-NL-8ZLmsg/s1600/trees_road.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4yowGdHG33ba_w7cy9lm42-adyRavLGJQZNfD01IANrXCLgDpx6SrucfXbZxpPLHIXzi9Hlut0QHAJaAfSKAdSE4zdxwFPm2zkoIyh-3qbVzFXTbV_MhXRBuul1s1A_Wt-NL-8ZLmsg/s1600/trees_road.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;h3&gt;
The Useful&lt;/h3&gt;
&lt;a href=&quot;http://flippinawesome.org/2013/12/09/demystifying-this-in-javascript/&quot;&gt;Demystifying this in JavaScript&lt;/a&gt; — as it says on the tine, a brief overview of how “this” is handled in JS. Some interesting nuances with it (or, shall I say, this) depending on the way you call a function, and also ways to override it (this!) if needed. Also, the article has a GIF that is both one of the funniest and one of the saddest at the same time.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://hanselman.com/tools&quot;&gt;Scott Hanselman&#39;s 2014 Ultimate Developer and Power Users Tool List for Windows&lt;/a&gt; — a huge (no exaggeration) list of Windows tools and tweaks, often offering several options. A good read to see if you&#39;ve missed any of recent (or old) developments. I am sure to go back to this list every once in a while.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.ostraining.com/blog/general/how-to-write-at-work/&quot;&gt;How to write at work&lt;/a&gt; — business communication is something I do all the time at work, so not much new here frankly, yet I greatly enjoy more people talking about how to write properly. The sad part is that people who really need to see such advice probably don&#39;t care. The main message, as always, is think (!) before you hit that “Send”.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
The Thoughtful&lt;/h3&gt;
&lt;a href=&quot;http://www.linkedin.com/today/post/article/20131216153414-266437464-how-to-make-a-deal-in-3-seconds-part-2&quot;&gt;&#39;Marines Don&#39;t Do That&#39;: Mastering The Split-Second Decision&lt;/a&gt; — I&#39;ll put this under “Work”, since sticking to our principles is what matters in the end. Especially if you believe in God, yet for everyone else too.&amp;nbsp;Would you be comfortable telling your children what you’re planning to do? Will you sleep well? Will you be able to calm your conscience year down the road, when the money earned by an immoral decision is already spent, and all you&#39;re left with is yourself?&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.thedailybeast.com/articles/2014/01/05/the-smartest-book-about-our-digital-age-was-published-in-1929.html&quot;&gt;The Smartest Book About Our Digital Age Was Published in 1929&lt;/a&gt; — I find this parallel fascinating (not everyone does, and a brief FB argument sparked to life about this article), as well as the general observation of the world turning its back on educated opinion in less precise fields. If you need a site made — you&#39;ll take someone with experience. If you need a music commentary — you&#39;ll rather trust someone who splashes in the same kiddie pool as you are in, over someone who&#39;ll attempt to take you to new heights. This is how I behave, too, sadly. Applies to everything with at least one level of abstraction.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
The Interesting&lt;/h3&gt;
&lt;a href=&quot;http://www.youtube.com/watch?feature=player_embedded&amp;amp;v=8j39NqwL7s4&quot;&gt;How to draw gesture&lt;/a&gt;&amp;nbsp;— a lot of such videos around, yet this one concentrates on 30 seconds and 2 minute poses, what shortcuts are required, how motion is emphasised (over contour), with a lot of quick examples (note that this is N-e-SFW — not entirely safe for work). Need to do more of these, I never managed to get into the habit.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.youtube.com/watch?v=QRBzl9FbJP0&quot;&gt;How it&#39;s made: Piano&lt;/a&gt;&amp;nbsp;— unfortunately a lower-resolution video, yet still very impressive. How much time, care and precision goes into making one of the most beautiful instruments in the world!&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
The Bizarre&lt;/h3&gt;
&lt;a href=&quot;http://www.dailydot.com/lifestyle/time-travelers-search-academic-paper/&quot;&gt;This is an actual academic paper about tracking time travelers online&lt;/a&gt; — sharing this in the hopes of promoting the idea so that, perhaps, some future readers notice this and post the requested hashtags in the past. If they do, though, I will not need to post this link anymore, so in the new future they will not find out about the hashtags, and then… Doc, help me out here!&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/5099878250429835337/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2014/01/reading-digest-01.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/5099878250429835337'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/5099878250429835337'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2014/01/reading-digest-01.html' title='Reading digest 01'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4yowGdHG33ba_w7cy9lm42-adyRavLGJQZNfD01IANrXCLgDpx6SrucfXbZxpPLHIXzi9Hlut0QHAJaAfSKAdSE4zdxwFPm2zkoIyh-3qbVzFXTbV_MhXRBuul1s1A_Wt-NL-8ZLmsg/s72-c/trees_road.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-6137526575699852813</id><published>2014-01-03T12:01:00.000+02:00</published><updated>2014-01-15T11:17:14.523+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="design"/><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="web stack"/><title type='text'>Drawing the colour wheel with JavaScript</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;h2 class=&quot;intro&quot;&gt;A brief follow-up to my earlier post on &lt;a href=&quot;http://www.amaslo.com/2013/12/automatic-colour-generation-in.html&quot;&gt;automatically generating colours using JavaScript&lt;/a&gt;, I just couldn&#39;t stop! It slightly irritated me that I had to search online for a picture of the colour wheel for the previous article (and found it on Kuler web-site, which is cool and all, but…), while I could easily generate it myself!&lt;/h2&gt;
So, here&#39;s what I came up with, adding some niceties:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg70V1Pm1rquYEpYV9UL07iRX-f9KYVLsJ-6YRqmLJsKr_eB-_em59aXFO_qaflBn91kmcY53orayXO1TgD_XdlG1Y4YhGVKRf9kUAkRtuufP361y70KvhHdGueyU9KEjj8RPk5lPyI2Q/s1600/colour_wheel_javascript.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg70V1Pm1rquYEpYV9UL07iRX-f9KYVLsJ-6YRqmLJsKr_eB-_em59aXFO_qaflBn91kmcY53orayXO1TgD_XdlG1Y4YhGVKRf9kUAkRtuufP361y70KvhHdGueyU9KEjj8RPk5lPyI2Q/s1600/colour_wheel_javascript.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
This is an example of using a scripting language for quick prototyping and demos, so the approach is not the most efficient performance-wise, but gave me a quick result. The main thing I would change if it were needed for actual usage — I would not use the DOM for individual “pixels”, this is a luxury. Canvas is a better candidate for such things.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
The Code&lt;/h3&gt;
Here&#39;s the working example of &lt;a href=&quot;http://jsfiddle.net/NPC42/Sk9kV/&quot;&gt;JSFiddle&lt;/a&gt;, and the important snippets are below:&lt;br /&gt;
&lt;pre style=&quot;background: #000000; color: #d1d1d1;&quot;&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; dim &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;51&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt; &lt;span style=&quot;color: #9999a9;&quot;&gt;// Beware of setting too high&lt;/span&gt;
&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; html &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;

&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; i &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt; i &lt;span style=&quot;color: #d2cd86;&quot;&gt;&amp;lt;&lt;/span&gt; dim&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt; i&lt;span style=&quot;color: #d2cd86;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
    &lt;span style=&quot;color: #9999a9;&quot;&gt;// Draw row&lt;/span&gt;
    &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; j &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt; j &lt;span style=&quot;color: #d2cd86;&quot;&gt;&amp;lt;&lt;/span&gt; dim&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt; j&lt;span style=&quot;color: #d2cd86;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
        &lt;span style=&quot;color: #9999a9;&quot;&gt;// Draw pixel&lt;/span&gt;
        html &lt;span style=&quot;color: #d2cd86;&quot;&gt;+=&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;&amp;lt;span class=&quot;pixel&#39;&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;j &lt;span style=&quot;color: #d2cd86;&quot;&gt;==&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;?&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39; first&#39;&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; 
        &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;&quot; style=&quot;background-color: &#39;&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; getColour&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;i&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt;j&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt;dim&lt;span style=&quot;color: #d2cd86;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #008c00;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; 
        &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;&quot;&amp;gt;&amp;lt;/span&amp;gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
    &lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;
&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;

$&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;#wheel&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;append&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;html&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;

&lt;span style=&quot;color: #9999a9;&quot;&gt;// Returns colour of pixel based on its offset&lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;//   and circle&#39;s radius (square width / 2)&lt;/span&gt;
&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt; getColour&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;i&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; j&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; radius&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
    &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; angle&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
    &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; col &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;#fff&#39;&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
    &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; x &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; j &lt;span style=&quot;color: #d2cd86;&quot;&gt;-&lt;/span&gt; radius&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
    &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; y &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; radius &lt;span style=&quot;color: #d2cd86;&quot;&gt;-&lt;/span&gt; i&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
    
    &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; dist &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; Math&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;sqrt&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;x&lt;span style=&quot;color: #d2cd86;&quot;&gt;*&lt;/span&gt;x &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; y&lt;span style=&quot;color: #d2cd86;&quot;&gt;*&lt;/span&gt;y&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
    
    &lt;span style=&quot;color: #9999a9;&quot;&gt;// If inside the circle&lt;/span&gt;
    &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;dist &lt;span style=&quot;color: #d2cd86;&quot;&gt;&amp;lt;=&lt;/span&gt; radius&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
        angle &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; Math&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;round&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #008c00;&quot;&gt;180&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;*&lt;/span&gt; Math&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;acos&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;x &lt;span style=&quot;color: #d2cd86;&quot;&gt;/&lt;/span&gt; dist&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;/&lt;/span&gt; Math&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;PI 
           &lt;span style=&quot;color: #d2cd86;&quot;&gt;*&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;y &lt;span style=&quot;color: #d2cd86;&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;?&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;1&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #008c00;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;
           &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;90&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
        col &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;hsl(&#39;&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; angle &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;, &#39;&lt;/span&gt; 
           &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;Math&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;round&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;dist &lt;span style=&quot;color: #d2cd86;&quot;&gt;/&lt;/span&gt; radius &lt;span style=&quot;color: #d2cd86;&quot;&gt;*&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;%, &#39;&lt;/span&gt; 
           &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #008c00;&quot;&gt;80&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;-&lt;/span&gt; Math&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;round&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;dist &lt;span style=&quot;color: #d2cd86;&quot;&gt;/&lt;/span&gt; radius &lt;span style=&quot;color: #d2cd86;&quot;&gt;*&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;%)&#39;&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
    &lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;
    
    &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;return&lt;/span&gt; col&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;br /&gt;
And you need this CSS to have the pixels align correctly:&lt;br /&gt;
&lt;pre style=&quot;background: #000000; color: #d1d1d1;&quot;&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;pixel &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
    &lt;span style=&quot;color: #904050;&quot;&gt;display&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;:&lt;/span&gt; block&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
    &lt;span style=&quot;color: #904050;&quot;&gt;float&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;:&lt;/span&gt; left&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
    &lt;span style=&quot;color: #904050;&quot;&gt;height&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #00a800;&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color: #006600;&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
    &lt;span style=&quot;color: #904050;&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #00a800;&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color: #006600;&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
    &lt;span style=&quot;color: #904050;&quot;&gt;margin&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #00a800;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #00a800;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #006600;&quot;&gt;px&lt;/span&gt; &lt;span style=&quot;color: #00a800;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #006600;&quot;&gt;px&lt;/span&gt; &lt;span style=&quot;color: #00a800;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
    border-radius&lt;span style=&quot;color: #d2cd86;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #00a800;&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color: #006600;&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;

&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;first &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
    &lt;span style=&quot;color: #904050;&quot;&gt;clear&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;:&lt;/span&gt; left&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Calculations&lt;/h3&gt;
The logic is simple — remember those trigonometry classes, the ones you couldn&#39;t understand why you will ever need them? Why, for drawing colour wheels, of course!&lt;br /&gt;
&lt;br /&gt;
I am drawing a square (wait), and for each pixel from its (x, y) coordinates I detect whether it is within the radius of the circle (see?). If not — draw pixel white (could make it transparent too, if I needed). Distance from the circle origin is the square root of sum of squares of the coordinates. This distance also determines saturation of the resulting colour, and a slight variation of lightness (that makes it look nicer).&lt;br /&gt;
&lt;br /&gt;
The hue is the angle of direction to the pixel compared to the vertical. To determine this I use arccosine — inversion of cosine value (school strikes back). Keep in mind that this gives you result in rads (full circle is two Pi), not degrees, so I still need to convert it.&lt;br /&gt;
&lt;br /&gt;
Put angle and distance together to get a colour — and voila, — you get the nice-looking wheel.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Playing Around&lt;/h3&gt;
With some time, inspiration and luck there can be many variations of the resulting picture:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitlPCgIjVvhbsEG2WoE0T_0JCdIBeeJNeFMkqXcdYdCKdGVYzchgL7rROObWdvmeKMJqvKoqyow6N-wTO4IvYz9HDYvmteEgOl4oa1XDjzHxHIGHC0kquXMjqEcLKMvGqCHKt5V-gT2g/s1600/colour_wheel_javascript_variations.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitlPCgIjVvhbsEG2WoE0T_0JCdIBeeJNeFMkqXcdYdCKdGVYzchgL7rROObWdvmeKMJqvKoqyow6N-wTO4IvYz9HDYvmteEgOl4oa1XDjzHxHIGHC0kquXMjqEcLKMvGqCHKt5V-gT2g/s1600/colour_wheel_javascript_variations.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
…or even the “proper” wheel:&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm7ktltNgfc1OJvvM3xZAcWC6lTCdqQR0Uw0DIHj6ssvignQFModOJB6XYPBTxu_cXmHHi96HafRukpurU0crCMsa0PoNZcYg4sv7XbuAMYagY1kdkMMvNTnn1pplmCloQOgCANquTMw/s1600/colour_wheel_javascript_proper.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm7ktltNgfc1OJvvM3xZAcWC6lTCdqQR0Uw0DIHj6ssvignQFModOJB6XYPBTxu_cXmHHi96HafRukpurU0crCMsa0PoNZcYg4sv7XbuAMYagY1kdkMMvNTnn1pplmCloQOgCANquTMw/s1600/colour_wheel_javascript_proper.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/6137526575699852813/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2014/01/drawing-colour-wheel-with-javascript.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/6137526575699852813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/6137526575699852813'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2014/01/drawing-colour-wheel-with-javascript.html' title='Drawing the colour wheel with JavaScript'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg70V1Pm1rquYEpYV9UL07iRX-f9KYVLsJ-6YRqmLJsKr_eB-_em59aXFO_qaflBn91kmcY53orayXO1TgD_XdlG1Y4YhGVKRf9kUAkRtuufP361y70KvhHdGueyU9KEjj8RPk5lPyI2Q/s72-c/colour_wheel_javascript.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-4491126655794181601</id><published>2013-12-30T14:46:00.000+02:00</published><updated>2014-01-15T11:16:19.935+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="css"/><category scheme="http://www.blogger.com/atom/ns#" term="design"/><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="ui"/><category scheme="http://www.blogger.com/atom/ns#" term="web stack"/><title type='text'>Automatic colour generation in JavaScript (with a trick!)</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;h2 class=&quot;intro&quot;&gt;The task — generate a number of sufficiently different colours for display on a page.&lt;/h2&gt;
&lt;br /&gt;
For example, this is needed to display a lot of elements, which belong to one of several categories (say, 10­-20 categories), and in colouring them you will help the viewer to easier identify elements of the same group.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Colour Theory&lt;/h3&gt;
The pep-talk version of it, anyway :)&lt;br /&gt;
&lt;br /&gt;
In web-world we are all used to the stock RGB (Red/Green/Blue) palette, yet it is in fact not the best choice. It works well for defining brightness of each of the three-coloured pixels on our screens, but it does not actually reflect nature of colour much. Try to manually create yellow out of that, for instance. Good luck.&lt;br /&gt;
&lt;br /&gt;
See, it is much easier to find differing colours on what is called a “Colour Wheel” (invented by some really smart person, I am sure), where different colour hues (tints) are signified by an angle out of 360 degrees (a circle indeed, hence a “wheel”):&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTTCFmP5P4384y8TaLyf1S4zt1l35t5bW7A8g4ilZApubsWZsJVcuZMz9v5b6uj1WfbYcr5L1m4WAZLTBN3mSvdBu70RCG8-nvAfXFyahnVq0eD39F-1P-NYWJDAtPEaXiKp-GjZyYUg/s1600/color_wheel_kuler.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTTCFmP5P4384y8TaLyf1S4zt1l35t5bW7A8g4ilZApubsWZsJVcuZMz9v5b6uj1WfbYcr5L1m4WAZLTBN3mSvdBu70RCG8-nvAfXFyahnVq0eD39F-1P-NYWJDAtPEaXiKp-GjZyYUg/s1600/color_wheel_kuler.jpg&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;b&gt;Da Wheel.&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;span id=&quot;goog_1865885356&quot;&gt;&lt;/span&gt;
If you pick a single hue value, then you can control how much of that colour is being displayed (Saturation), and how light/dark it is (Brightness). Very easy to find opposing / nearby / lighter / darker / whatever shades this way. This is why those artsy designer-types quite often (if not always) prefer an HSB format (stands for Hue / Saturation / Brightness) over RGB. This is like choosing English (a formal and precise subset of it) over Assembler programming language.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Equidistant Colours&lt;/h3&gt;
How does it help us? It helps a lot. In order to generate several colours that are as far from each other as possible, yet still possess similar lightness — i.e. to solve our basic problem of autogenerated set of differing colours, — we, in the very simple method, need to only pick different hue “angles” with the same saturation and brightness values.&lt;br /&gt;
&lt;br /&gt;
This is not precisely true, I&#39;ll explain below why, but good enough for now.&lt;br /&gt;
&lt;br /&gt;
And we have a huge blessing disguised in support of HSL format (Hue / Saturation / Lightness — lightness being synonymous to “brightness”, fine by me) by all modern browsers. Yay for technological progress!&lt;br /&gt;
&lt;br /&gt;
So, if we pick saturation and lightness at 80% and 70% respectively, if we need, say, 12 colours, we can just divide the 360° by 12 (yields step of 30°), and then plot them starting from zero. These values can be used as a background colour, in the following style declaration: “background-color: hsl(0, 80%, 70%)”.&lt;br /&gt;
&lt;br /&gt;
Easy.&lt;br /&gt;
&lt;br /&gt;
You&#39;ll see my code below, and this is the result I get from running it for 16 colours:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYf4N7u1863c1pL4a0F_T6j-xUmNhMt839RHONfCDvqk109sTEvCBufODm_dn_Z9bzXeC5EgXOVyh3-gQdwWuLUlLYhYvtXYX7nZdVjZJSfL8Wu2_bpgxQgnP4WR2cQhcjiegZOyQScA/s1600/autocolouring_basic_method_16.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYf4N7u1863c1pL4a0F_T6j-xUmNhMt839RHONfCDvqk109sTEvCBufODm_dn_Z9bzXeC5EgXOVyh3-gQdwWuLUlLYhYvtXYX7nZdVjZJSfL8Wu2_bpgxQgnP4WR2cQhcjiegZOyQScA/s1600/autocolouring_basic_method_16.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Not bad, huh?&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
The Trick&lt;/h3&gt;
It is okay, but being the grumpy type I have to say it could be better (and it&#39;ll never be ideal, oh well). Nearby colours, especially in the green range, are too close together visually. This is important if you have a poorly tuned monitor, or view it slightly off-normal angles (on cheaper screen types).&lt;br /&gt;
&lt;br /&gt;
Let&#39;s improve it. The hues are already equidistant, so you can&#39;t really gain much more contrast in picking the tint. Yet the immense variety of colours we see in real life is not achieved by hue alone!&lt;br /&gt;
&lt;br /&gt;
So the small trick I propose is to alternate between slightly different saturation/brightness values for adjacent colours — say, for even colours use SL of (80%, 75%), and for odd ones use (70%, 80%).&lt;br /&gt;
&lt;br /&gt;
This results in the following sequence (old one shown to the left, for comparison):&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7XYF2C9bFKHWaCdSjW19KWAd6P7BI0G8zlDrEE0zjneTIJ-ySZiTgeu9CXzWCk541rKsgclGQnJb11Uhyphenhyphenk3Nz1ncM9hPVQsmsy0Qdx6BMZd1YhnZGj2LRK4uAxQXsgvNI6PlLkKLv_A/s1600/autocolouring_trick_method_16.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7XYF2C9bFKHWaCdSjW19KWAd6P7BI0G8zlDrEE0zjneTIJ-ySZiTgeu9CXzWCk541rKsgclGQnJb11Uhyphenhyphenk3Nz1ncM9hPVQsmsy0Qdx6BMZd1YhnZGj2LRK4uAxQXsgvNI6PlLkKLv_A/s1600/autocolouring_trick_method_16.png&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;b&gt;Before — After*. &lt;/b&gt;&lt;br /&gt;
*Improvement guaranteed or your money back after 15 years of following this Simple Exercise Routine™!&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Better, I say. This can be tweaked further, depending on how many colours you need (perhaps you need to alternate every three colours, for example), and the actual saturation/brightness values will vary depending on the specific needs of your project — whether you need lighter or darker colours etc. Even hue range could be limited to a portion of the spectrum.&lt;br /&gt;
&lt;br /&gt;
I hope this gives you a good idea and a starting point for your own experiments.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
The Code&lt;/h3&gt;
You can check the working demo in the corresponding &lt;a href=&quot;http://jsfiddle.net/NPC42/PGFyb/&quot; rel=&quot;&quot;&gt;JSFiddle&lt;/a&gt; (I hope it lives long and prospers!).&lt;br /&gt;
&lt;br /&gt;
Here&#39;s the JS code, to give you an idea of what is happening:&lt;br /&gt;
&lt;pre style=&quot;background: #000000; color: #d1d1d1;&quot;&gt;$&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;#gen-btn&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;click&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;generate&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;

&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt; generate&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
 &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; genQty &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; $&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;#gen-qty&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;val&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
 
 populateList&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;#colour-show-1&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; genQty&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
 populateList&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;#colour-show-2&#39;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; genQty&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;

&lt;span style=&quot;color: #9999a9;&quot;&gt;// Creates an HTML demo list with generated colours&lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;// variant is the choice of which method to apply&lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;//   0 - basic; 1 - with the odd/even saturation/lightness trick&lt;/span&gt;
&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt; populateList&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;selector&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; qty&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; variant&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
 &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; html &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #02d045;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #02d045;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; colour&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
 &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; step &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; Math&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;floor&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #008c00;&quot;&gt;360&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;/&lt;/span&gt; qty&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;

 &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; i &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt; i &lt;span style=&quot;color: #d2cd86;&quot;&gt;&amp;lt;&lt;/span&gt; qty&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt; i&lt;span style=&quot;color: #d2cd86;&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
  colour &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; getColour&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;i&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; step&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; variant&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
  html &lt;span style=&quot;color: #d2cd86;&quot;&gt;+=&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;&amp;lt;li style=&quot;background-color: &#39;&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; colour &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;;&quot;&amp;gt;&amp;amp;nbsp;&amp;lt;/li&amp;gt;&#39;&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
 &lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;

 $&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;selector&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;html&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;html&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;

 &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;

&lt;span style=&quot;color: #9999a9;&quot;&gt;// Returns individual colour, based on its &lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;//   number in the sequence, &lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;//   the angular step, and &lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;//   the chosen method &lt;/span&gt;
&lt;span style=&quot;color: #9999a9;&quot;&gt;//   (0 - without or 1 - with the saturation/lightness trick)&lt;/span&gt;
&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;function&lt;/span&gt; getColour&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;num&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; step&lt;span style=&quot;color: #d2cd86;&quot;&gt;,&lt;/span&gt; variant&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
 &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;var&lt;/span&gt; col&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;

 &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;switch&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;variant&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;{&lt;/span&gt;
  &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;case&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;:&lt;/span&gt;
   col &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;hsl(&#39;&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;num &lt;span style=&quot;color: #d2cd86;&quot;&gt;*&lt;/span&gt; step&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;toString&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;, &#39;&lt;/span&gt; &lt;span style=&quot;color: #9999a9;&quot;&gt;// Hue&lt;/span&gt;
    &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;num &lt;span style=&quot;color: #d2cd86;&quot;&gt;%&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;2&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;==&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;?&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;80&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;75&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;%, &#39;&lt;/span&gt; &lt;span style=&quot;color: #9999a9;&quot;&gt;// Saturation, even/ odd&lt;/span&gt;
    &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;num &lt;span style=&quot;color: #d2cd86;&quot;&gt;%&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;2&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;==&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;?&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;70&lt;/span&gt; &lt;span style=&quot;color: #b060b0;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;80&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;%)&#39;&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt; &lt;span style=&quot;color: #9999a9;&quot;&gt;// Lightness, even/odd&lt;/span&gt;
   &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
  default&lt;span style=&quot;color: #b060b0;&quot;&gt;:&lt;/span&gt; col &lt;span style=&quot;color: #d2cd86;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;hsl(&#39;&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;num &lt;span style=&quot;color: #d2cd86;&quot;&gt;*&lt;/span&gt; step&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;toString&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #d2cd86;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #d2cd86;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #00c4c4;&quot;&gt;&#39;, 80%, 70%)&#39;&lt;/span&gt;&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
 &lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;

 &lt;span style=&quot;color: #e66170; font-weight: bold;&quot;&gt;return&lt;/span&gt; col&lt;span style=&quot;color: #b060b0;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #b060b0;&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Possible Improvements&lt;/h3&gt;
I would actually like to hear if you have any ideas on how this can be improved further. One observation I made earlier is that the colours in the green section are visually too close together — perhaps some nuance of how our (mine?) eye sees it. So we could gain better result by spreading that particular range further apart, while there is room to make red-orange, and blue-purple hues closer and still have them distinguishable.&lt;br /&gt;
&lt;br /&gt;
That&#39;s just an idea, though, and may be you&#39;ll have more. For now the simple version works for me, and it may work for you. Take care!&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/4491126655794181601/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2013/12/automatic-colour-generation-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/4491126655794181601'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/4491126655794181601'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2013/12/automatic-colour-generation-in.html' title='Automatic colour generation in JavaScript (with a trick!)'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTTCFmP5P4384y8TaLyf1S4zt1l35t5bW7A8g4ilZApubsWZsJVcuZMz9v5b6uj1WfbYcr5L1m4WAZLTBN3mSvdBu70RCG8-nvAfXFyahnVq0eD39F-1P-NYWJDAtPEaXiKp-GjZyYUg/s72-c/color_wheel_kuler.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-7516746692681864094</id><published>2013-12-04T11:40:00.000+02:00</published><updated>2014-01-15T11:17:50.959+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="communication"/><category scheme="http://www.blogger.com/atom/ns#" term="leadership"/><category scheme="http://www.blogger.com/atom/ns#" term="management"/><title type='text'>I wish for the customer to always be right</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;h2 class=&quot;intro&quot;&gt;The customer is always right!&lt;br /&gt;
&lt;br /&gt;
Right… like they&#39;re not human. Perhaps, humanity will be overrun not by perfect automatons created by SkyNet (or Hasbro&#39;s Furbies, whichever you prefer), but instead by the Infallible Customer (or did that already happen)! It&#39;s just not true.&lt;/h2&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQL5ET6q9NgjnrPh-ilXquasYbznAS-PXwVXvXveKHbMCP9P3pwvGNbmMH0FsN460oJRe95nDklcDtJ3qkMD2XNblBdy7NLvy2Ys8mSnnMdMLnH4YAWVqFH8AwO-Efd3JFOWjdgkzGYw/s1600/robot_overrun.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;202&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQL5ET6q9NgjnrPh-ilXquasYbznAS-PXwVXvXveKHbMCP9P3pwvGNbmMH0FsN460oJRe95nDklcDtJ3qkMD2XNblBdy7NLvy2Ys8mSnnMdMLnH4YAWVqFH8AwO-Efd3JFOWjdgkzGYw/s400/robot_overrun.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;b&gt;These are always right! In a cute&#39;n&#39;scary kind of way.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
(photo by &lt;a href=&quot;http://www.flickr.com/photos/the_justified_sinner/&quot; rel=&quot;nofollow&quot;&gt;The Justified Sinner&lt;/a&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;No, wait, it is true in the motivational sense!&lt;br /&gt;
&lt;br /&gt;
Say, you give a task to one of your developers (including your inner developer, hello!), and, upon studying it, he starts to grumble. Oh, so-and-so customer, again they are coming up with most stupid things to occupy us with, complicating everything: our product, our code, our testing, our very life! And on he goes on and on, stupid task, silly customer, smart me, and so on, and so forth.&lt;br /&gt;
&lt;br /&gt;
In such cases your are totally entitled to un-sheath the above slogan. The customer is right. They are the one who have a problem that needs solving, and they are the one, who will (hopefully) pay for this in the end. Also, they probably know their business much better than we do. So — study the task, try to understand the underlying problem, and solve it, instead of ceaselessly whining, thank you very much.&lt;br /&gt;
&lt;br /&gt;
But, apart from such inspired speeches, we need to keep in mind that the customer is, in fact, not always right. They just can&#39;t be. Nor, I noticed, do they always try to be.&lt;br /&gt;
&lt;br /&gt;
Think about it — they&#39;re busy with their work (just as you are with yours), they also have lots of tasks, priorities and distractions to manage On top of it, they may have a pressing problem (like, their boss forcing them to describe something to you, or even them facing an urgent issue which they really really hope you could help them solve), which adds to the stress.&lt;br /&gt;
&lt;br /&gt;
Plus, wait for it, they are not always as technically savvy as you pretend to be. So they can&#39;t really tell your “&lt;i&gt;current DB structure only allows for this&lt;/i&gt;” from “&lt;i&gt;JSON over AJAX with&amp;nbsp;jQuery from IE6&lt;/i&gt;”.&lt;br /&gt;
&lt;br /&gt;
And, if they are good and nice people, they also try to help you by describing their imagined solution to the problem, instead of describing the problem itself. It doesn&#39;t always help, yet they do try.&lt;br /&gt;
&lt;br /&gt;
Thus some inconsistencies in their requests: contradictions, omissions, odd fantasies and things that are just wrong. If we expect the “customer to be always right”, and, after a while of intensive arguments and hurt feelings, we just decide that, &lt;i&gt;right, I&#39;ve had it, I&#39;ll just do what they say, and then they will see that I was right all along!&lt;/i&gt; — we are not helping anyone. Not even ourselves.&lt;br /&gt;
&lt;br /&gt;
So — let&#39;s be merciful and gentle. Study the task carefully. Hold our horses on arguing, blaming and bashing. Try to &lt;i&gt;understand&lt;/i&gt;. And try to be &lt;i&gt;helpful&lt;/i&gt;. And just be humanely &lt;i&gt;nice&lt;/i&gt;, as much as it is possible.&lt;br /&gt;
&lt;br /&gt;
And, in my experience, the customers love it. You act like a member of their team, you worry about their problem like it is your problem (and indeed it is, if you&#39;re tasked to solve it), and, for all intents and purposes, you act like your customer is always right, by graciously allowing them to be wrong every once in a while.&lt;br /&gt;
&lt;br /&gt;
A bit of a rant, yes, but it is something I have to remind myself very very often, since my inner developer likes to complain no less than that other guy. This toxicity can be contained. Let&#39;s make this industry — and this world, — a better place to work in :)&lt;br /&gt;
&lt;br /&gt;
Take care!&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/7516746692681864094/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2013/12/i-wish-for-customer-to-always-be-right.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/7516746692681864094'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/7516746692681864094'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2013/12/i-wish-for-customer-to-always-be-right.html' title='I wish for the customer to always be right'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQL5ET6q9NgjnrPh-ilXquasYbznAS-PXwVXvXveKHbMCP9P3pwvGNbmMH0FsN460oJRe95nDklcDtJ3qkMD2XNblBdy7NLvy2Ys8mSnnMdMLnH4YAWVqFH8AwO-Efd3JFOWjdgkzGYw/s72-c/robot_overrun.jpg" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-7160487956180946896</id><published>2013-11-13T13:39:00.000+02:00</published><updated>2014-01-15T11:19:05.293+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="css"/><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><title type='text'>Multiple columns in HTML/CSS (and JS for poor old Internet Explorer)</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;h2 class=&quot;intro&quot;&gt;A quickie on how I solved a need to display multiple columns, before I forget (and may be helpful to some of you, my dear readers).&lt;br /&gt;
&lt;br /&gt;
The problem — I have a dynamically generated text (parameter fields in a settings form), which I need to display on the screen utilising as much width as possible. If the fields were not dynamically created, it would of course be better to layout the form manually — then you can make intelligent choices about what goes where. Not in this case, though, so I needed an automated way to display this content in columns.&lt;/h2&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Cascade Style Sheet FTW!&lt;/h3&gt;
Of course, there is CSS3, which is really cool and can do it nicely and fairly easily:&lt;br /&gt;
&lt;pre style=&quot;background: #f6f8ff; color: #000020;&quot;&gt;&lt;span style=&quot;color: #308080;&quot;&gt;#&lt;/span&gt;content
&lt;span style=&quot;color: #406080;&quot;&gt;{&lt;/span&gt;
    -moz-column-count&lt;span style=&quot;color: #308080;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color: #406080;&quot;&gt;;&lt;/span&gt;
    -moz-column-gap&lt;span style=&quot;color: #308080;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color: #006600;&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color: #406080;&quot;&gt;;&lt;/span&gt;
    -webkit-column-count&lt;span style=&quot;color: #308080;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color: #406080;&quot;&gt;;&lt;/span&gt;
    -webkit-column-gap&lt;span style=&quot;color: #308080;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color: #006600;&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color: #406080;&quot;&gt;;&lt;/span&gt;
    column-count&lt;span style=&quot;color: #308080;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color: #406080;&quot;&gt;;&lt;/span&gt;
    column-gap&lt;span style=&quot;color: #308080;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color: #006600;&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color: #406080;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #406080;&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;column-count&lt;/b&gt; defines how many columns CSS will attempt to lay the content out (utilising the width that is available to the element), &lt;b&gt;column-gap&lt;/b&gt; is the margin between the columns. Of course there is the -moz and -webkit prefix madness that we&#39;ve all learnt to expect already.&lt;br /&gt;
&lt;br /&gt;
This works surprisingly well on all desktop browsers (didn&#39;t test on mobile, not required for this project, yet I hope the newer ones will render this too… or — see below), except for… drumroll… opening the envelope… ah, you knew it already — IE9 and below.&lt;br /&gt;
&lt;br /&gt;
Poor things, they&#39;ve worked enough and need their rest, but people keep using them. Anyway, we need a solution that would work on these too.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
JavaScript FTW!&lt;/h3&gt;
I don&#39;t go with a JS solution for everything because it is less transparent (and, therefore, error-prone and harder to fix if things go wrong in some obscure situation), may slow the page down, and, well, is not the tool for the job. Unless you&#39;re on IE.&lt;br /&gt;
&lt;br /&gt;
So, I used a combination of &lt;a href=&quot;http://welcome.totheinter.net/columnizer-jquery-plugin/&quot;&gt;Columnizer&lt;/a&gt; (a jQuery plugin) and &lt;a href=&quot;http://modernizr.com/&quot;&gt;Modernizr&lt;/a&gt; (what&#39;s with all the -zr fashion?).&lt;br /&gt;
&lt;br /&gt;
Modernizr is a very nice library that can be used to detect support of the CSS columns feature, and, if it is not present, introduce a fallback to JS.&lt;br /&gt;
&lt;br /&gt;
Even better — and I love this part, — Modernizr can load the Columnizer library if it is required — so this improves page load time for the browsers that do support columns. Here&#39;s how it is done (in your JS code, on page load):&lt;br /&gt;
&lt;pre style=&quot;background: #f6f8ff; color: #000020;&quot;&gt;Modernizr&lt;span style=&quot;color: #308080;&quot;&gt;.&lt;/span&gt;load&lt;span style=&quot;color: #308080;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #406080;&quot;&gt;{&lt;/span&gt;
   &lt;span style=&quot;color: #200080; font-weight: bold;&quot;&gt;test&lt;/span&gt;&lt;span style=&quot;color: #406080;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #308080;&quot;&gt;!&lt;/span&gt;Modernizr&lt;span style=&quot;color: #308080;&quot;&gt;.&lt;/span&gt;csscolumns&lt;span style=&quot;color: #308080;&quot;&gt;,&lt;/span&gt;
   yep&lt;span style=&quot;color: #406080;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #1060b6;&quot;&gt;&#39;/js/jquery.columnizer.js&#39;&lt;/span&gt;&lt;span style=&quot;color: #308080;&quot;&gt;,&lt;/span&gt;
   nope&lt;span style=&quot;color: #406080;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #1060b6;&quot;&gt;&#39;&#39;&lt;/span&gt;
&lt;span style=&quot;color: #406080;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #308080;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #406080;&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
Very simple — we test support for CSS columns, and if not supported — load the additional JS code.&lt;br /&gt;
&lt;br /&gt;
Note that the &lt;b&gt;.load&lt;/b&gt; method is not included in Modernizr development build (a very odd decision, I&#39;d say), so if you plan on using this feature — you need to select it in the main Modernizr download builder (in the Extras section).&lt;br /&gt;
&lt;br /&gt;
Now, where you need to apply the columns, you can use the following JS code:&lt;br /&gt;
&lt;pre style=&quot;background: #f6f8ff; color: #000020;&quot;&gt;&lt;span style=&quot;color: #200080; font-weight: bold;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #308080;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #308080;&quot;&gt;!&lt;/span&gt;Modernizr&lt;span style=&quot;color: #308080;&quot;&gt;.&lt;/span&gt;csscolumns &lt;span style=&quot;color: #308080;&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; $&lt;span style=&quot;color: #308080;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #1060b6;&quot;&gt;&#39;#content .column&#39;&lt;/span&gt;&lt;span style=&quot;color: #308080;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #308080;&quot;&gt;.length&lt;/span&gt; &lt;span style=&quot;color: #308080;&quot;&gt;==&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #308080;&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #406080;&quot;&gt;{&lt;/span&gt;
   $&lt;span style=&quot;color: #308080;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #1060b6;&quot;&gt;&#39;#content&#39;&lt;/span&gt;&lt;span style=&quot;color: #308080;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #308080;&quot;&gt;.&lt;/span&gt;columnize&lt;span style=&quot;color: #308080;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #406080;&quot;&gt;{&lt;/span&gt; columns&lt;span style=&quot;color: #406080;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;3&lt;/span&gt; &lt;span style=&quot;color: #406080;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #308080;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #406080;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #406080;&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
What it does is again check whether CSS columns are supported, and applies columnization (isn&#39;t a word, I know) to our element of choice, to create three columns. The element in my case may be shown multiple times, and this script is called each time, this is why I check for presence of &lt;b&gt;.column&lt;/b&gt; class in our element ($(&#39;#content .column&#39;).length equals zero) — Columnizer add this class to its generated columns for easy styling, and thus I can also detect whether it has done its job before or not.&lt;br /&gt;
&lt;br /&gt;
Note that I am not checking “if the browser is IE” — this is the beauty of Modernizr. Instead we can check for support of a specific feature, so this will work on other browsers that don&#39;t support it, not just limited to IE (I am thinking about older mobile browsers here). Nice, isn&#39;t it?&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Then I just need to apply my column-gap style to the HTML generated by JS:&lt;/div&gt;
&lt;pre style=&quot;background: #f6f8ff; color: #000020;&quot;&gt;&lt;span style=&quot;color: #308080;&quot;&gt;#&lt;/span&gt;content &lt;span style=&quot;color: #308080;&quot;&gt;.&lt;/span&gt;column &lt;span style=&quot;color: #595979;&quot;&gt;/* Needed for columns created by the Columnizer script */&lt;/span&gt;
&lt;span style=&quot;color: #406080;&quot;&gt;{&lt;/span&gt;
   &lt;span style=&quot;color: #7779bb; font-weight: bold;&quot;&gt;padding-right&lt;/span&gt;&lt;span style=&quot;color: #308080;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #008c00;&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color: #006600;&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color: #406080;&quot;&gt;;&lt;/span&gt;
   -webkit-box-sizing&lt;span style=&quot;color: #308080;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #008484;&quot;&gt;border-box&lt;/span&gt;&lt;span style=&quot;color: #406080;&quot;&gt;;&lt;/span&gt;
   &lt;span style=&quot;color: #008484;&quot;&gt;-moz-box-sizing&lt;/span&gt;&lt;span style=&quot;color: #308080;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #008484;&quot;&gt;border-box&lt;/span&gt;&lt;span style=&quot;color: #406080;&quot;&gt;;&lt;/span&gt;
   box-sizing&lt;span style=&quot;color: #308080;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #008484;&quot;&gt;border-box&lt;/span&gt;&lt;span style=&quot;color: #406080;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #406080;&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;box-sizing&lt;/b&gt;&amp;nbsp;(with unavoidable entourage of prefixes) is needed to make sure the padding does not increase the width of the columns, or else it all falls apart.&lt;br /&gt;
&lt;br /&gt;
That&#39;s it, it works :)&lt;br /&gt;
&lt;br /&gt;
This is obviously not the only solution, something may suit you better in your situation. On another occasion I needed more complex rules for splitting items between columns, so had to write my own JavaScript code to handle the whole thing.&lt;br /&gt;
&lt;br /&gt;
Let me know if you have any feedback / questions, and take care.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/7160487956180946896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2013/11/multiple-columns-in-htmlcss-and-js-for.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/7160487956180946896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/7160487956180946896'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2013/11/multiple-columns-in-htmlcss-and-js-for.html' title='Multiple columns in HTML/CSS (and JS for poor old Internet Explorer)'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7008386140022030691.post-3237463113884130865</id><published>2013-07-25T16:20:00.000+03:00</published><updated>2014-01-15T11:20:33.145+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="leadership"/><category scheme="http://www.blogger.com/atom/ns#" term="management"/><title type='text'>A Fire-and-Forget Worker</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;h2 class=&quot;intro&quot;&gt;This is not about a worker whom you fire and then easily forget about (with a sigh of relief, perhaps?). No, this is quite different. You know them&amp;nbsp;&lt;a href=&quot;http://en.wikipedia.org/wiki/Fire-and-forget&quot;&gt;fire-and-forget missiles&lt;/a&gt;? Their key strength is that they don&#39;t require additional guidance after being fired. Point them to the target, give a brief motivational speech, and off they go! Now imagine this for people and their tasks.&lt;/h2&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2IQRTvPd-LgIMoQYJpyf6-MZbOwpvbdps_UvkRn2sRzu19JnPKcEpHocP5PiNj69L5gYWrvAhB5N_hQ7hyu0yEC-xYNP-Xb0YqGyYJxqPDf5pyLWahaI7ZvxqZ3bxb1kpS73Eu6M-Rw/s1600/fire-and-forget-missile.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2IQRTvPd-LgIMoQYJpyf6-MZbOwpvbdps_UvkRn2sRzu19JnPKcEpHocP5PiNj69L5gYWrvAhB5N_hQ7hyu0yEC-xYNP-Xb0YqGyYJxqPDf5pyLWahaI7ZvxqZ3bxb1kpS73Eu6M-Rw/s1600/fire-and-forget-missile.jpg&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;b&gt;…and Tony Stark can turn his back to the explosion — to spread his hands in triumph :)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;There are many qualities of a truly good professional, yet close to the top of the list (somewhere along with ability to listen and &lt;a href=&quot;http://www.amaslo.com/2012/08/study-study-learn.html&quot;&gt;learn&lt;/a&gt;) is the ability to take your task (or, shall we say, a “mission”!) and then do it.&lt;br /&gt;
&lt;br /&gt;
Yes, there may be issues along the way — you&#39;ll make sure to solve them. You don&#39;t even need to do it yourself — there may be additional approvals or decisions required, so you&#39;ll go and talk to the required people and see to it that the decisions are made, etc etc. And you&#39;ll then check the result before clapping your hands together for a happy “Another job well done!”, since you&#39;re probably the best person to check your work for potential weak spots, omissions or &lt;a href=&quot;http://www.amaslo.com/2012/06/ancient-art-of-corner-cutting.html&quot;&gt;cut corners&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
This is as opposed to sitting on your soft… chair (or &lt;a href=&quot;http://www.amaslo.com/2013/01/my-standing-desk-experiment.html&quot;&gt;standing on your hard floor&lt;/a&gt;, if you prefer) and building up a list of excuses for every obstacle you encounter, waiting for someone to come along and ask whether you&#39;re moving according to plan — and helping you overcome whatever minor issue you decided was good enough to relax for now. This is as opposed to &lt;a href=&quot;http://www.amaslo.com/2012/06/to-question-or-not-to-question-that-is.html&quot;&gt;sending avalanches of emails&lt;/a&gt; to ensure that “the ball isn&#39;t in your court” at any given time. This is as opposed to people who need a lot of hand-holding (not a good thing, even if it sounds romantic) to get through their projects.&lt;br /&gt;
&lt;br /&gt;
Why is this helpful to your colleagues? If they don&#39;t need to double- and triple-check you — they are freed to work on their tasks, and, as a team, you achieve more.&lt;br /&gt;
&lt;br /&gt;
Why is this helpful to you? Well, interestingly, you&#39;ll notice that such people get quickly noticed in a work environment, and, if the environment is at least somewhat healthy, their position improves. They get more trust, more things depend on them, so, as such people are reliable, so is their job and — gasp! — even their salary.&lt;br /&gt;
&lt;br /&gt;
So even if you&#39;re ambitious and have lofty goals — I&#39;d say that being &lt;b&gt;dependable&lt;/b&gt; is an honest, morally right and emotionally satisfying way to get to where you want to be. As opposed to, say, playing cover-my-ass&amp;nbsp;or career-ladder games and all that shameful nonsense that we see probably too often.&lt;br /&gt;
&lt;br /&gt;
Therefore I&#39;ll definitely strive to be more of this kind of person, and encourage you to do the same.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.amaslo.com/feeds/3237463113884130865/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.amaslo.com/2013/07/a-fire-and-forget-worker.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/3237463113884130865'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7008386140022030691/posts/default/3237463113884130865'/><link rel='alternate' type='text/html' href='http://www.amaslo.com/2013/07/a-fire-and-forget-worker.html' title='A Fire-and-Forget Worker'/><author><name>Anton</name><uri>http://www.blogger.com/profile/06383611247281695315</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2IQRTvPd-LgIMoQYJpyf6-MZbOwpvbdps_UvkRn2sRzu19JnPKcEpHocP5PiNj69L5gYWrvAhB5N_hQ7hyu0yEC-xYNP-Xb0YqGyYJxqPDf5pyLWahaI7ZvxqZ3bxb1kpS73Eu6M-Rw/s72-c/fire-and-forget-missile.jpg" height="72" width="72"/><thr:total>2</thr:total></entry></feed>