<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>Mika Tuupola - blog</title>
  <id>tag:www.appelsiini.net,2009:mephisto/</id>
  <generator uri="http://mephistoblog.com" version="0.8.0">Mephisto Drax</generator>
  <link href="http://www.appelsiini.net/feed/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="http://www.appelsiini.net/" rel="alternate" type="text/html"/>
  <updated>2009-05-29T11:57:04Z</updated>
  <entry xml:base="http://www.appelsiini.net/">
    <author>
      <name>tuupola</name>
    </author>
    <id>tag:www.appelsiini.net,2009-05-18:4179</id>
    <published>2009-05-18T09:17:00Z</published>
    <updated>2009-05-29T11:57:04Z</updated>
    <category term="frog"/>
    <category term="php"/>
    <link href="http://www.appelsiini.net/2009/5/logging-api-for-frog-dashboard" rel="alternate" type="text/html"/>
    <title>Logging API for Frog Dashboard</title>
<summary type="html">&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2009/5/15/dashboard.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://www.appelsiini.net/projects/dashboard&quot;&gt;Dashboard plugin&lt;/a&gt; for Frog &lt;span class=&quot;caps&quot;&gt;CMS&lt;/span&gt; now provides simple &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; for other developers to log their events. Whenever you want to log something to dashboard just trigger  a log event. Include your message as parameter.&lt;/p&gt;


&lt;pre&gt;
Observer::notify('log_event', 'Something was done by :username.');
&lt;/pre&gt;

	&lt;p&gt;In your message you can include string :username to log the user name.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2009/5/15/dashboard.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://www.appelsiini.net/projects/dashboard&quot;&gt;Dashboard plugin&lt;/a&gt; for Frog &lt;span class=&quot;caps&quot;&gt;CMS&lt;/span&gt; now provides simple &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; for other developers to log their events. Whenever you want to log something to dashboard just trigger  a log event. Include your message as parameter.&lt;/p&gt;


&lt;pre&gt;
Observer::notify('log_event', 'Something was done by :username.');
&lt;/pre&gt;

	&lt;p&gt;In your message you can include string :username to log the user name.&lt;/p&gt;
&lt;h3&gt;Priority and Ident&lt;/h3&gt;


	&lt;p&gt;You can also provide priority and ident for the log message. Priority is used to inform about severity of the message. Ident is used to identify sender of the message. Plugin developers should use the ident of their plugin. For example &lt;a href=&quot;http://www.appelsiini.net/projects/funky_cache&quot;&gt;Funky Cache&lt;/a&gt; plugin uses &lt;em&gt;funky_cache&lt;/em&gt; as ident.&lt;/p&gt;


&lt;pre&gt;
Observer::notify('log_event', 'Something else was done by :username.',
                               DASHBOARD_LOG_NOTICE, 'pluginname');
&lt;/pre&gt;

	&lt;p&gt;Priorities are defined in Dashboard code.&lt;/p&gt;


&lt;pre&gt;
define('DASHBOARD_LOG_EMERG',    0); /* system no longer available */
define('DASHBOARD_LOG_ALERT',    1); /* immediate action required */
define('DASHBOARD_LOG_CRIT',     2); /* critical condition */
define('DASHBOARD_LOG_ERR',      3); /* error condition */
define('DASHBOARD_LOG_WARNING',  4); /* warning messages */
define('DASHBOARD_LOG_NOTICE',   5); /* normal, but significant, condition */
define('DASHBOARD_LOG_INFO',     6); /* general informative messages */
define('DASHBOARD_LOG_DEBUG',    7); /* debugging information */
&lt;/pre&gt;

	&lt;p&gt;If your code uses constants and Frog is in debug mode and Dashboard plugin is not installed this will cause &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; to display &lt;em&gt;&#8220;Use of undefined constant&#8221;&lt;/em&gt; warnings.  If you want to be sure your user will never see these warnings you can use number  instead of constant:&lt;/p&gt;


&lt;pre&gt;
Observer::notify('log_event', 'Something else was done by :username.',
                               4, 'pluginname');
&lt;/pre&gt;

	&lt;p&gt;You could also define the constants yourself. But make sure they are not already defined (Dashboard installed). Defining constants twice will cause warnings.&lt;/p&gt;


	&lt;h3&gt;Download&lt;/h3&gt;


	&lt;p&gt;Download the &lt;a href=&quot;http://www.appelsiini.net/download/frog_assets.tar.gz&quot;&gt;latest tarball&lt;/a&gt; or checkout from &lt;a href=&quot;http://github.com/tuupola/frog_dashboard&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.appelsiini.net/">
    <author>
      <name>tuupola</name>
    </author>
    <id>tag:www.appelsiini.net,2009-04-20:3138</id>
    <published>2009-04-20T13:21:00Z</published>
    <updated>2009-04-20T13:22:18Z</updated>
    <link href="http://www.appelsiini.net/2009/4/bloggers-meeting-at-altex" rel="alternate" type="text/html"/>
    <title>Bloggers Meeting at Altex</title>
<summary type="html">&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2009/4/17/bloggers.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Altex together with &lt;a href=&quot;http://konverentsid-ee.z132.zone.ee/?nodeid=3&amp;amp;#38;lang=et&amp;amp;#38;item=14502&quot; title=&quot;Marketing Conference&quot;&gt;Pärnu Turunduskonverets&lt;/a&gt; organized a small bloggers meeting. Aim was to discuss same subjects which will be present in the real conference.&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;How to achieve big things in Internet with small amount of money?&lt;/li&gt;
		&lt;li&gt;How to convince your boss to invest in online marketing?&lt;/li&gt;
		&lt;li&gt;How to achieve competitive edge during recession?&lt;/li&gt;
		&lt;li&gt;Who will survive recession better &#8211; online or offline stores?&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;&lt;em&gt;&lt;span class=&quot;caps&quot;&gt;DISCLOSURE&lt;/span&gt;: People who attended the bloggers were kindly asked (but not required) to mention and link to the conference page in a blog entry. Least we can do as a thanks to nice food and beverages.&lt;/em&gt;&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2009/4/17/bloggers.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Altex together with &lt;a href=&quot;http://konverentsid-ee.z132.zone.ee/?nodeid=3&amp;amp;#38;lang=et&amp;amp;#38;item=14502&quot; title=&quot;Marketing Conference&quot;&gt;Pärnu Turunduskonverets&lt;/a&gt; organized a small bloggers meeting. Aim was to discuss same subjects which will be present in the real conference.&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;How to achieve big things in Internet with small amount of money?&lt;/li&gt;
		&lt;li&gt;How to convince your boss to invest in online marketing?&lt;/li&gt;
		&lt;li&gt;How to achieve competitive edge during recession?&lt;/li&gt;
		&lt;li&gt;Who will survive recession better &#8211; online or offline stores?&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;&lt;em&gt;&lt;span class=&quot;caps&quot;&gt;DISCLOSURE&lt;/span&gt;: People who attended the bloggers were kindly asked (but not required) to mention and link to the conference page in a blog entry. Least we can do as a thanks to nice food and beverages.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Money Money Money&lt;/h3&gt;


	&lt;p&gt;Us having short attention span discussion varied a bit. With money talk we figured out everything costs something. Blogging might seem like its free but when you put pricetag to your time it is not so cheap anymore. There was also some discussion of age old problem people thinking that because Internet equals computers it must equal cheap to do.&lt;/p&gt;


	&lt;p&gt;One issue which raised was how Estonian generally avoid using Paypal. It is for some reason found to be cumbersome to use (which I and others did not agree). There might be trust issues. Since Paypal is not any of the local banks (which are owned by Swedes anyway) it is not trusted.&lt;/p&gt;


	&lt;p&gt;In off topic discussion some had noted that there are problems sending properly Google tagged banners links to media. Long links usually get broken because advertising section cut and pastes only half of the &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt;.&lt;/p&gt;


	&lt;h3&gt;Conference&lt;/h3&gt;


	&lt;p&gt;But this blog post was supposed to be about the conference. On friday 15th of May the interesting parts are.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;caps&quot;&gt;SMALL BUDGET&lt;/span&gt;, BIG &lt;span class=&quot;caps&quot;&gt;BENEFIT&lt;/span&gt; &#8211; &lt;span class=&quot;caps&quot;&gt;EXPERIENCE FROM SOCIAL NETWORKS&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;
Hille Hinsberg, Estonian goverment &#38; Epp-Kristiina Keerov, Altex&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;caps&quot;&gt;WHAT DO PEOPLE DO IN THE INTERNET&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;
Anni Ronkainen, Google&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;caps&quot;&gt;HOW TO SELL E&lt;/span&gt;-MARKETING &lt;span class=&quot;caps&quot;&gt;TO YOUR BOSS&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;
Craig Hanna, e-consultancy.com&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;caps&quot;&gt;WILL RECESSION KILL OFFLINE OR ONLINE BUSINESS&lt;/span&gt;?&lt;/strong&gt;&lt;br /&gt; 
Aivar Paalberg, Enter IT&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.appelsiini.net/">
    <author>
      <name>tuupola</name>
    </author>
    <id>tag:www.appelsiini.net,2009-04-09:2717</id>
    <published>2009-04-09T15:08:00Z</published>
    <updated>2009-05-15T14:46:56Z</updated>
    <category term="estonia"/>
    <category term="work"/>
    <link href="http://www.appelsiini.net/2009/4/state-of-kuldmuna-digital-and-what-to-do-about-it" rel="alternate" type="text/html"/>
    <title>State of Kuldmuna Digital and What To Do About It?</title>
<summary type="html">&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2009/4/9/kuldmunad.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Last weekend Kuldmuna awards were given out. Someone is going to be offended by saying this. Level of most of entries shortlisted in &lt;a href=&quot;http://eral.vertical.ee/index.php?page=finalists&amp;amp;#38;id=29&quot;&gt;Internet design&lt;/a&gt; and &lt;a href=&quot;http://eral.vertical.ee/index.php?page=finalists&amp;amp;#38;id=24&quot;&gt;Digital advertising&lt;/a&gt; categories were shamefully low. I know there have been better projects in Estonia during last year. How did this happen?&lt;/p&gt;


	&lt;p&gt;&lt;em&gt;&lt;span class=&quot;caps&quot;&gt;DISCLAIMER&lt;/span&gt;: I work in advertising agency myself. I have been working in advertising agency or online department of advertising agency for last 11 years. Good to remember when you work in advertising and feel offended by reading this.&lt;/em&gt;&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2009/4/9/kuldmunad.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Last weekend Kuldmuna awards were given out. Someone is going to be offended by saying this. Level of most of entries shortlisted in &lt;a href=&quot;http://eral.vertical.ee/index.php?page=finalists&amp;amp;#38;id=29&quot;&gt;Internet design&lt;/a&gt; and &lt;a href=&quot;http://eral.vertical.ee/index.php?page=finalists&amp;amp;#38;id=24&quot;&gt;Digital advertising&lt;/a&gt; categories were shamefully low. I know there have been better projects in Estonia during last year. How did this happen?&lt;/p&gt;


	&lt;p&gt;&lt;em&gt;&lt;span class=&quot;caps&quot;&gt;DISCLAIMER&lt;/span&gt;: I work in advertising agency myself. I have been working in advertising agency or online department of advertising agency for last 11 years. Good to remember when you work in advertising and feel offended by reading this.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Kuldmuna Is an Advertising Competition&lt;/h3&gt;


	&lt;p&gt;This is the main reason. Kuldmuna is about advertising by advertising people. You can see it from the beginning. When submitting your project only names of project manager, copywriter, AD and creative director are asked. Same problem continues in the website and in the Kuldmuna book.&lt;/p&gt;


	&lt;p&gt;It might be surprising to some but in web projects there is much more. Frontend coder, backend coder and Flash designer are first to come into mind. With larger projects information architect, UI designer and UX designer might be involved. If nothing else please just add one field called &lt;em&gt;Technical designer&lt;/em&gt; for these people.&lt;/p&gt;


	&lt;h3&gt;Judging With Advertising Mindset&lt;/h3&gt;


	&lt;p&gt;Entries get judged with advertising mindset. In worst case just by showing a screenshot or presentation of a site. Judges don&#8217;t always have time or possibility to click through the site. We are not even talking about checking code quality here. It ends up being a beauty competition.&lt;/p&gt;


	&lt;p&gt;Easiest way to win is to make full Flash site with flying stuff and sounds. Even better if you invent some new &#8220;innovative&#8221; navigation. This is sometimes done in purpose. Agencies do separate projects which are good in Internet sense. Other projects which are just done for winning awards.&lt;/p&gt;


	&lt;p&gt;Smart agencies have learned what to submit to advertising competition. Good online projects do not get submitted to an advertising competition. They won&#8217;t win anything anyway.&lt;/p&gt;


	&lt;h3&gt;What To Do About It?&lt;/h3&gt;


	&lt;p&gt;We had exactly the same problem in Finland. Solution was &lt;a href=&quot;http://www.rekaksois.com/grandone/&quot;&gt;Grand One&lt;/a&gt;. We could do exactly the same here in Estonia &#8211; Our own online awards organized and judged by online people.&lt;/p&gt;


	&lt;p&gt;I am willing to invest my own time and money for this. I just need some native Estonian speaker to join me (I do speak Estonian, just suck at writing it).&lt;/p&gt;


	&lt;h3&gt;Starting Steps&lt;/h3&gt;


	&lt;p&gt;I already figured out name for the awards. I have discussed the name with Estonian colleagues and everyone approved the idea. Name of the competition would be &lt;strong&gt;&#8220;Au tööle!&#8221;&lt;/strong&gt;.&lt;/p&gt;


	&lt;p&gt;To start things quickly &lt;a href=&quot;http://twitter.com/autoole&quot;&gt;Au tööle! Twitter channel&lt;/a&gt; was set up. Purpose of this channel is to have place which lists what online projects agencies are doing. Yes, there is &lt;a href=&quot;http://pixel.ee/&quot;&gt;pixel.ee&lt;/a&gt; but only some projects are submitted there. To add your project send a private tweet or email &lt;a href=&quot;mailto:lisa@autoole.ee&quot;&gt;lisa@autoole.ee&lt;/a&gt;. Send the following info:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Name of the project&lt;/li&gt;
		&lt;li&gt;&lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; to the project&lt;/li&gt;
		&lt;li&gt;Name of the company(ies) who created it&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;This solves another problem we have. Lots of projects get done without other agencies knowing about them. It is nice to know what other are doing. Please send recent projects. Do not spam with everything you have done during last year.&lt;/p&gt;


	&lt;p&gt;If Twitter channel becomes we could start giving out smaller awards. Once a month might be too often. Every other month is a good start. Winner would be chosen by three judges. New judges are chosen each time. Judges will come from different agencies and there should be at least one designer and one coder.&lt;/p&gt;


	&lt;p&gt;Beginning of next year would be the first gala. Up to here everything has been free. Companies submitting projects to main event would have to pay a fee. There should be one category for non-profits or bloggers where entrance fee is free. Categories would be:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Best campaign&lt;/li&gt;
		&lt;li&gt;Best online service&lt;/li&gt;
		&lt;li&gt;Best design&lt;/li&gt;
		&lt;li&gt;Best online ad (banners etc)&lt;/li&gt;
		&lt;li&gt;Grand Prix&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h3&gt;How Do You Feel About It?&lt;/h3&gt;


	&lt;p&gt;What do you think? You think I am crazy? It will never work? You would like to help? One thing is for sure &#8211; something needs to be done. If you have any ideas or suggestion leave a comment (in english or estonian).&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.appelsiini.net/">
    <author>
      <name>tuupola</name>
    </author>
    <id>tag:www.appelsiini.net,2009-02-13:2481</id>
    <published>2009-02-13T10:21:00Z</published>
    <updated>2009-03-20T12:48:00Z</updated>
    <category term="jquery"/>
    <link href="http://www.appelsiini.net/2009/2/lazy-load-inside-container" rel="alternate" type="text/html"/>
    <title>Lazy Load Inside Container</title>
<content type="html">
            &lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2009/2/13/gazillion_photos.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://silentmatt.com/&quot;&gt;Matthew Crumley&lt;/a&gt; contributed nice patch to &lt;a href=&quot;http://www.appelsiini.net/projects/lazyload&quot;&gt;Lazy Load&lt;/a&gt; plugin which makes it work with containers. If you have a container which has a scrollbar.&lt;/p&gt;


&lt;pre&gt;
#container {
    height: 600px;
    overflow: scroll;
}
&lt;/pre&gt;

	&lt;p&gt;Images which are not visible are not loaded until you scroll to them. Check demo page for &lt;a href=&quot;http://www.appelsiini.net/projects/lazyload/enabled_container.html&quot;&gt;horizontal&lt;/a&gt; and &lt;a href=&quot;http://www.appelsiini.net/projects/lazyload/enabled_wide_container.html&quot;&gt;vertical&lt;/a&gt; scrolling.&lt;/p&gt;


	&lt;p&gt;To use new feature you can give the container as jQuery object.&lt;/p&gt;


&lt;pre&gt;
$(&quot;img&quot;).lazyload({         
     placeholder : &quot;img/grey.gif&quot;,
     container: $(&quot;#container&quot;)
 });
&lt;/pre&gt;

	&lt;p&gt;Mathew also patched a bug where IE was not always loading images. To upgrade download the latest &lt;a href=&quot;http://www.appelsiini.net/download/jquery.lazyload.js&quot;&gt;source&lt;/a&gt;, &lt;a href=&quot;http://www.appelsiini.net/download/jquery.lazyload.mini.js&quot;&gt;minified&lt;/a&gt; or &lt;a href=&quot;http://www.appelsiini.net/download/jquery.lazyload.pack.js&quot;&gt;packed&lt;/a&gt;.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.appelsiini.net/">
    <author>
      <name>tuupola</name>
    </author>
    <id>tag:www.appelsiini.net,2009-02-09:2435</id>
    <published>2009-02-09T21:56:00Z</published>
    <updated>2009-04-13T13:03:19Z</updated>
    <category term="jquery"/>
    <link href="http://www.appelsiini.net/2009/2/search-jquery-api-docs-from-spotlight" rel="alternate" type="text/html"/>
    <title>Search jQuery API Docs from Spotlight</title>
<summary type="html">&lt;p&gt;Yesterday &lt;a href=&quot;http://www.priithaamer.com/&quot;&gt;Priit Haamer&lt;/a&gt; of Fraktal notified me about &lt;a href=&quot;http://priithaamer.com/blog/ruby-on-rails-dictionary-for-macosx&quot;&gt;Spotlight searchable Ruby on Rails documentation&lt;/a&gt; he had made. Absolutely brilliant idea. When I saw it I knew I have to do same thing for jQuery.&lt;/p&gt;


	&lt;h3&gt;Why Is It cool?&lt;/h3&gt;


	&lt;p&gt;You can just hit &lt;b&gt;Apple + Space&lt;/b&gt; to enter spotlight and search for jQuery function.&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2009/2/9/jquery_spotlight.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Press and hold &lt;b&gt;Apple + Control + D&lt;/b&gt; over any function in TextMate (or Safari, iChat, Mail etc.) to get info popup.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;Yesterday &lt;a href=&quot;http://www.priithaamer.com/&quot;&gt;Priit Haamer&lt;/a&gt; of Fraktal notified me about &lt;a href=&quot;http://priithaamer.com/blog/ruby-on-rails-dictionary-for-macosx&quot;&gt;Spotlight searchable Ruby on Rails documentation&lt;/a&gt; he had made. Absolutely brilliant idea. When I saw it I knew I have to do same thing for jQuery.&lt;/p&gt;


	&lt;h3&gt;Why Is It cool?&lt;/h3&gt;


	&lt;p&gt;You can just hit &lt;b&gt;Apple + Space&lt;/b&gt; to enter spotlight and search for jQuery function.&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2009/2/9/jquery_spotlight.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Press and hold &lt;b&gt;Apple + Control + D&lt;/b&gt; over any function in TextMate (or Safari, iChat, Mail etc.) to get info popup.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2009/2/9/jquery-ctrl-apple-d.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Docs are in your harddrive so they are always accessible. Even when you or docs.jquery.com are offline.&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2009/2/9/jquery_entry.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;It is native, based on &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt; dictionary. No need to install &lt;span class=&quot;caps&quot;&gt;AIR&lt;/span&gt; or any other applications.&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2009/2/9/jquery_search.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;h3&gt;Install From Zip&lt;/h3&gt;


	&lt;p&gt;Download &lt;a href=&quot;http://www.appelsiini.net/download/jQuery.dictionary.zip&quot; title=&quot;184KB&quot;&gt;jQuery.dictionary.zip&lt;/a&gt; file. Unzip it and move to folder &lt;strong&gt;~/Library/Dictionaries&lt;/strong&gt; or  &lt;strong&gt;/Library/Dictionaries&lt;/strong&gt;. Enable it from Dictionary preferences.&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2009/2/9/jquery_enable.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Sometimes it takes a while for Spotlight to see new dictionary. You can speed things up by restarting it.&lt;/p&gt;


&lt;pre&gt;
&amp;gt;killall Spotlight
&lt;/pre&gt;

	&lt;p&gt;According to Priit you should also drag new dictionary to be first on the list. This was not true in my case. However if you have problems it is worth trying.&lt;/p&gt;


	&lt;h3&gt;Install From Git&lt;/h3&gt;


	&lt;p&gt;If you like to live in bleeding edge install from Git and build your own.&lt;/p&gt;


&lt;pre&gt;
&amp;gt;git clone git://github.com/tuupola/jquery_dictionary.git
&amp;gt;cd jquery_dictionary
&amp;gt;make
&amp;gt;make install
&lt;/pre&gt;

	&lt;h3&gt;Acknowledgements&lt;/h3&gt;


	&lt;p&gt;Thanks to Priit Haamer for the &lt;a href=&quot;http://priithaamer.com/blog/ruby-on-rails-dictionary-for-macosx&quot;&gt;original idea&lt;/a&gt;. David Serduke for the the &lt;a href=&quot;http://jqueryjs.googlecode.com/svn/trunk/tools/wikiapi2xml/createjQueryXMLDocs.py&quot;&gt;Python script&lt;/a&gt; used  exporting  jQuery wiki to &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt; format. Jörn Zaefferer whose &lt;a href=&quot;http://jqueryjs.googlecode.com/svn/trunk/tools/api-browser/style.xsl&quot;&gt;&lt;span class=&quot;caps&quot;&gt;XSLT&lt;/span&gt; stylesheets&lt;/a&gt; were used as basis for &lt;span class=&quot;caps&quot;&gt;XSLT&lt;/span&gt; stylesheet which converts exported jQuery docs to &lt;span class=&quot;caps&quot;&gt;OS X&lt;/span&gt; dictionary &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt; source&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.appelsiini.net/">
    <author>
      <name>tuupola</name>
    </author>
    <id>tag:www.appelsiini.net,2008-12-23:2128</id>
    <published>2008-12-23T15:50:00Z</published>
    <updated>2008-12-23T15:51:35Z</updated>
    <category term="frog"/>
    <category term="php"/>
    <link href="http://www.appelsiini.net/2008/12/mephisto-style-asset-management-for-frog-cms" rel="alternate" type="text/html"/>
    <title>Mephisto Style Asset Management for Frog CMS</title>
<content type="html">
            &lt;p&gt;One of the things I like about &lt;a href=&quot;http://mephistoblog.com/&quot;&gt;Mephisto&lt;/a&gt; is the asset management. Especially the way how you insert image URLs by dragging thumbnail from sidebar to content area. &lt;a href=&quot;http://www.madebyfrog.com/&quot;&gt;Frog &lt;span class=&quot;caps&quot;&gt;CMS&lt;/span&gt;&lt;/a&gt; lacked easy way for inserting images (or any other files). Obvious thing to do was implement Mephisto style asset management as a plugin.&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2008/12/22/assets_page.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;It is not one to one copy on how Mephisto does it. Instead of tagging assets you can categorize them by uploading to different folders. There is also extra pulldown to select which assets to show in sidebar while editing.&lt;/p&gt;


	&lt;p&gt;Plugin depends on &lt;a href=&quot;http://github.com/naehrstoff/image_resize&quot;&gt;Image Resize&lt;/a&gt; and &lt;a href=&quot;http://github.com/tuupola/frog_jquery&quot;&gt;jQuery&lt;/a&gt; plugins to work.  Full installation instructions on &lt;a href=&quot;http://www.appelsiini.net/projects/frog_assets&quot;&gt;project page&lt;/a&gt;.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.appelsiini.net/">
    <author>
      <name>tuupola</name>
    </author>
    <id>tag:www.appelsiini.net,2008-11-28:2080</id>
    <published>2008-11-28T15:04:00Z</published>
    <updated>2009-01-20T21:29:28Z</updated>
    <category term="frog"/>
    <category term="php"/>
    <link href="http://www.appelsiini.net/2008/11/send-emails-from-frog-cms" rel="alternate" type="text/html"/>
    <title>Send Emails from Frog CMS</title>
<content type="html">
            &lt;p&gt;I needed a mailer backend which can handle complicated forms with any number of arbitary form fields. I also needed to be able to fully control the layout of sent emails. Something similar as oldie but goldie &lt;a href=&quot;http://web.mit.edu/wwwdev/cgiemail/&quot;&gt;cgiemail&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Here comes &lt;a href=&quot;http://www.appelsiini.net/projects/email_template&quot;&gt;Email Template&lt;/a&gt; plugin for &lt;a href=&quot;http://www.madebyfrog.com/&quot;&gt;Frog &lt;span class=&quot;caps&quot;&gt;CMS&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;It provides new page type called named &lt;em&gt;Email template&lt;/em&gt;. You can &lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt; your forms to this page type. Page contains the layout of the mail including the headers. Template then parses &lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt;:ed data and sends the email.&lt;/p&gt;


&lt;pre&gt;
To: Somebody &amp;lt;somebody@example.com&amp;gt;
From: &amp;lt;?php print $_POST['name'] ?&amp;gt; &amp;lt;&amp;lt;?php print $_POST['email'] ?&amp;gt;&amp;gt;
Subject: Frog Mail

1. Contact info

Name.............: &amp;lt;?php print $_POST['name'] ?&amp;gt; 
Company..........: &amp;lt;?php print $_POST['company'] ?&amp;gt; 
Email............: &amp;lt;?php print $_POST['email'] ?&amp;gt; 

2. Message

&amp;lt;?php print $_POST['message'] ?&amp;gt;

--
Sent by &amp;lt;?php print $_SERVER['REMOTE_ADDR'] ?&amp;gt;
&lt;/pre&gt;

	&lt;p&gt;Plugin assumes your &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; mail() function works properly. Currently it only supports plain text emails. &lt;a href=&quot;http://www.appelsiini.net/projects/email_template&quot;&gt;Download and installation instructions&lt;/a&gt; at the project page. All feedback welcome.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.appelsiini.net/">
    <author>
      <name>tuupola</name>
    </author>
    <id>tag:www.appelsiini.net,2008-11-21:2069</id>
    <published>2008-11-21T15:51:00Z</published>
    <updated>2009-01-20T21:29:12Z</updated>
    <category term="frog"/>
    <category term="php"/>
    <link href="http://www.appelsiini.net/2008/11/ultrafast-frog-with-funky-cache" rel="alternate" type="text/html"/>
    <title>Ultrafast Frog With Funky Cache</title>
<summary type="html">&lt;p&gt;&lt;img src=&quot;http://chart.apis.google.com/chart?chs=540x120&amp;amp;#38;chf=bg,s,ffffff|c,s,ffffff&amp;amp;#38;chxt=x,y&amp;amp;#38;chxl=1:|FunkyCache|FileCache|NoCache|0:|0.00|879.00|1,758.00&amp;amp;#38;cht=bhg&amp;amp;#38;chd=t:5.34,8.47,100.00&amp;amp;#38;chco=4d89f9&amp;amp;#38;chbh=25&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Funky caching is technique popularized by &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;.net site. It was first mentioned by Rasmus Lerdorf in &lt;a href=&quot;http://www.lerdorf.com/tips.pdf&quot;&gt;2002 PHPCon slides&lt;/a&gt; (page 25). Content is cached as static file on the first access. All following requests are served using the cached static file. Editing a page will automatically expire cached files. Page is then re-cached on the next hit.&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://www.madebyfrog.com/&quot;&gt;Frog &lt;span class=&quot;caps&quot;&gt;CMS&lt;/span&gt;&lt;/a&gt; is &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; port of Rails based &lt;a href=&quot;http://radiantcms.org/&quot;&gt;Radiant &lt;span class=&quot;caps&quot;&gt;CMS&lt;/span&gt;&lt;/a&gt;. Radiant is great but there is always the hosting problem. Even with mod_rails existing it is still easier to get quality &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; hosting. Both Frog and Radiant are the only &lt;span class=&quot;caps&quot;&gt;CMS&lt;/span&gt;&#8217;es I can say I like. Expression Engine I can live with. &lt;a href=&quot;http://www.edicy.com/&quot;&gt;Edicy&lt;/a&gt; looks really promising. Everything else I rather not touch.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;&lt;img src=&quot;http://chart.apis.google.com/chart?chs=540x120&amp;amp;#38;chf=bg,s,ffffff|c,s,ffffff&amp;amp;#38;chxt=x,y&amp;amp;#38;chxl=1:|FunkyCache|FileCache|NoCache|0:|0.00|879.00|1,758.00&amp;amp;#38;cht=bhg&amp;amp;#38;chd=t:5.34,8.47,100.00&amp;amp;#38;chco=4d89f9&amp;amp;#38;chbh=25&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Funky caching is technique popularized by &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;.net site. It was first mentioned by Rasmus Lerdorf in &lt;a href=&quot;http://www.lerdorf.com/tips.pdf&quot;&gt;2002 PHPCon slides&lt;/a&gt; (page 25). Content is cached as static file on the first access. All following requests are served using the cached static file. Editing a page will automatically expire cached files. Page is then re-cached on the next hit.&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://www.madebyfrog.com/&quot;&gt;Frog &lt;span class=&quot;caps&quot;&gt;CMS&lt;/span&gt;&lt;/a&gt; is &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; port of Rails based &lt;a href=&quot;http://radiantcms.org/&quot;&gt;Radiant &lt;span class=&quot;caps&quot;&gt;CMS&lt;/span&gt;&lt;/a&gt;. Radiant is great but there is always the hosting problem. Even with mod_rails existing it is still easier to get quality &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; hosting. Both Frog and Radiant are the only &lt;span class=&quot;caps&quot;&gt;CMS&lt;/span&gt;&#8217;es I can say I like. Expression Engine I can live with. &lt;a href=&quot;http://www.edicy.com/&quot;&gt;Edicy&lt;/a&gt; looks really promising. Everything else I rather not touch.&lt;/p&gt;
&lt;h3&gt;How About the Speed?&lt;/h3&gt;


	&lt;p&gt;Frog is reasonably fast. Simple ApacheBench running on localhost (to rule out network latency) shows it can deliver around 90 requests per second.&lt;/p&gt;


&lt;pre&gt;
&amp;gt; ab -n 1000 -c 20 http://dev.example.com/about_us.html

Time taken for tests:   10.600109 seconds
Requests per second:    94.34 [#/sec] (mean)
Time per request:       212.002 [ms] (mean)
Time per request:       10.600 [ms] (mean, across all concurrent requests)
Transfer rate:          255.66 [Kbytes/sec] received
&lt;/pre&gt;

	&lt;p&gt;I have seen slower. This would not stand Digg effect though.&lt;/p&gt;


	&lt;h3&gt;File Cache Plugin&lt;/h3&gt;


	&lt;p&gt;Using Gilles Doge&#8217;s &lt;a href=&quot;http://www.antistatique.net/blog/index.php/post/cache-plugin-frogcms&quot;&gt;File Cache plugin&lt;/a&gt; gives improvement. Test server gives 150 requests per second. Problem is requests are still routed to backend. &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; logic decides whether to show cached contents or not.&lt;/p&gt;


&lt;pre&gt;
&amp;gt; ab -n 1000 -c 20 http://dev.example.com/about_us.html

Time taken for tests:   6.707378 seconds
Requests per second:    149.09 [#/sec] (mean)
Time per request:       134.148 [ms] (mean)
Time per request:       6.707 [ms] (mean, across all concurrent requests)
Transfer rate:          617.08 [Kbytes/sec] received
&lt;/pre&gt;

	&lt;p&gt;This still would not stand Digg effect.&lt;/p&gt;


	&lt;h3&gt;Enter Funky Cache Plugin&lt;/h3&gt;


	&lt;p&gt;Something needed to be done. Since I have had good experiences with &lt;a href=&quot;http://mephistoblog.com/&quot;&gt;Mephisto&lt;/a&gt; which uses funky caching I decided to give it a try. This is where Frog first showed its power. Software was totally new to me. Still their plugin &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; was so clear to understand I was able to create first working version in one evening. Second evening was spent polishing the code.&lt;/p&gt;


	&lt;p&gt;So does it work? With Funky Caching enabled test server delivered 1750 requests per second.&lt;/p&gt;


&lt;pre&gt;
&amp;gt; ab -n 1000 -c 20 http://dev.example.com/about_us.html

Time taken for tests:   0.568727 seconds
Requests per second:    1758.31 [#/sec] (mean)
Time per request:       11.375 [ms] (mean)
Time per request:       0.569 [ms] (mean, across all concurrent requests)
Transfer rate:          7284.69 [Kbytes/sec] received
&lt;/pre&gt;

	&lt;p&gt;That should be enough to withstand both Digg effect and Slashdotting at the same time.&lt;/p&gt;


	&lt;h3&gt;Yes Gimme Some!&lt;/h3&gt;


	&lt;p&gt;&lt;a href=&quot;http://www.appelsiini.net/projects/funky_cache&quot;&gt;Installation instructions&lt;/a&gt; at project page. If you want to peek under the hood check the source at &lt;a href=&quot;http://github.com/tuupola/frog_funky_cache&quot;&gt;GitHub&lt;/a&gt;. Code is still beta quality. Please leave a comment if you find a bug or you have improvement ideas.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.appelsiini.net/">
    <author>
      <name>tuupola</name>
    </author>
    <id>tag:www.appelsiini.net,2008-11-04:1954</id>
    <published>2008-11-04T20:13:00Z</published>
    <updated>2009-02-12T14:21:32Z</updated>
    <category term="google"/>
    <category term="maps"/>
    <category term="php"/>
    <link href="http://www.appelsiini.net/2008/11/introduction-to-marker-clustering-with-google-maps" rel="alternate" type="text/html"/>
    <title>Introduction to Marker Clustering With Google Maps</title>
<summary type="html">&lt;p&gt;Static Maps &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; has &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; length limit of around 2048 characters. You can hit this limit quickly when adding lot of markers. You can keep &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; short by clustering markers together.&lt;/p&gt;


	&lt;h3&gt;Square Based Clustering&lt;/h3&gt;


	&lt;p&gt;Clustering is usually done by dividing map to squares. Square size depends on map zoom level. Markers inside a square are then grouped into cluster. This technique has some limitations. Look at the following image.&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2008/11/2/square_fail.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Two markers are close to each other. In fact they are so close they are overlapping. Both markers are also the only marker inside their square. Because markers are in separate square they wont be clustered.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;Static Maps &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; has &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; length limit of around 2048 characters. You can hit this limit quickly when adding lot of markers. You can keep &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; short by clustering markers together.&lt;/p&gt;


	&lt;h3&gt;Square Based Clustering&lt;/h3&gt;


	&lt;p&gt;Clustering is usually done by dividing map to squares. Square size depends on map zoom level. Markers inside a square are then grouped into cluster. This technique has some limitations. Look at the following image.&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2008/11/2/square_fail.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Two markers are close to each other. In fact they are so close they are overlapping. Both markers are also the only marker inside their square. Because markers are in separate square they wont be clustered.&lt;/p&gt;
&lt;h3&gt;Distance Based Clustering&lt;/h3&gt;


	&lt;p&gt;We can also group markers together based on their distance from each other. We could cluster all markers inside 10 kilometer radius together. There is one problem with this approach. Kilometers (and miles) have different meaning in different zoom levels. In zoomed in map it might mean 100 pixels. In zoomed out maps one kilometer might be only one pixel.&lt;/p&gt;


	&lt;p&gt;There is only one distance unit which does not have this problem: pixels in current zoom level. One pixel on screen is always one pixel on screen. For example we want to cluster all markers which are 20 pixels from each other. I chose 20 pixels because it happens to be the distance after which markers start to overlap each other.&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2008/11/2/distance_great_success.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Now the two markers would be clustered since they are inside 20 pixel radius.&lt;/p&gt;


	&lt;h3&gt;Distance Between Two Coordinates on Earth&lt;/h3&gt;


	&lt;p&gt;Distance between two points on earth can be calculated in several ways. &lt;a href=&quot;http://en.wikipedia.org/wiki/Haversine_formula&quot;&gt;Haversine formula&lt;/a&gt; is reasonably accurate and widely used. It assumes earth is spherical (in reality earth is slightly ellipsoid). This causes accuracy to be +-2 km when calculating distances of around 20.000 km. 6371.0 km is used as average radius of earth.&lt;/p&gt;


	&lt;p&gt;Below is &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; implementation of Haversine formula:&lt;/p&gt;


&lt;pre&gt;
function haversineDistance($lat1, $lon1, $lat2, $lon2) {
    $latd = deg2rad($lat2 - $lat1);
    $lond = deg2rad($lon2 - $lon1);
    $a = sin($latd / 2) * sin($latd / 2) +
         cos(deg2rad($lat1)) * cos(deg2rad($lat2)) *
         sin($lond / 2) * sin($lond / 2);
         $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
    return 6371.0 * $c;
}
&lt;/pre&gt;

	&lt;p&gt;But didn&#8217;t wee need distance in pixels instead? For that we can use &lt;a href=&quot;http://en.wikipedia.org/wiki/Pythagorean_theorem#Distance_in_Cartesian_coordinates&quot;&gt;Pythagoras&#8217; theorem&lt;/a&gt;. Pythagoras&#8217; theorem uses cartesian (pixel) coordinates. Some &lt;a href=&quot;http://en.wikipedia.org/wiki/Mercator_projection&quot;&gt;Mercator&lt;/a&gt; magic can be used to convert latitude and longitude to pixel x and y values.&lt;/p&gt;


	&lt;p&gt;You might wonder where did number 268435456 come from? It is half of the earth circumference in pixels at zoom level 21. You can visualize it by thinking of full map. Full map size is 536870912 × 536870912 pixels. Center of the map in pixel coordinates is 268435456,268435456 which in latitude and longitude would be 0,0.&lt;/p&gt;


&lt;pre&gt;
define('OFFSET', 268435456);
define('RADIUS', 85445659.4471); /* $offset / pi() */

function lonToX($lon) {
    return round(OFFSET + RADIUS * $lon * pi() / 180);        
}

function latToY($lat) {
    return round(OFFSET - RADIUS * 
                log((1 + sin($lat * pi() / 180)) / 
                (1 - sin($lat * pi() / 180))) / 2);
}

function pixelDistance($lat1, $lon1, $lat2, $lon2, $zoom) {
    $x1 = lonToX($lon1);
    $y1 = latToY($lat1);

    $x2 = lonToX($lon2);
    $y2 = latToY($lat2);

    return sqrt(pow(($x1-$x2),2) + pow(($y1-$y2),2)) &amp;gt;&amp;gt; (21 - $zoom);
}
&lt;/pre&gt;

	&lt;p&gt;Now we have all needed mathematics in place. What to do with them?&lt;/p&gt;


	&lt;h3&gt;Cluster Markers Together&lt;/h3&gt;


	&lt;p&gt;Let&#8217;s write example clusterer function. It takes three parameters:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Array of &lt;em&gt;lat&lt;/em&gt; and &lt;em&gt;lon&lt;/em&gt; locations. &lt;/li&gt;
		&lt;li&gt;Distance in pixel inside which markers will be clustered.&lt;/li&gt;
		&lt;li&gt;Current map zoom level.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Function will return another array where coordinates closer than &lt;em&gt;$distance&lt;/em&gt; are clustered together.&lt;/p&gt;


&lt;pre&gt;
function cluster($markers, $distance, $zoom) {
    $clustered = array();
    /* Loop until all markers have been compared. */
    while (count($markers)) {
        $marker  = array_pop($markers);
        $cluster = array();
        /* Compare against all markers which are left. */
        foreach ($markers as $key =&amp;gt; $target) {
            $pixels = pixelDistance($marker['lat'], $marker['lon'],
                                    $target['lat'], $target['lon'],
                                    $zoom);
            /* If two markers are closer than given distance remove */
            /* target marker from array and add it to cluster.      */
            if ($distance &amp;gt; $pixels) {
                printf(&quot;Distance between %s,%s and %s,%s is %d pixels.\n&quot;, 
                    $marker['lat'], $marker['lon'],
                    $target['lat'], $target['lon'],
                    $pixels);
                unset($markers[$key]);
                $cluster[] = $target;
            }
        }

        /* If a marker has been added to cluster, add also the one  */
        /* we were comparing to and remove the original from array. */
        if (count($cluster) &amp;gt; 0) {
            $cluster[] = $marker;
            $clustered[] = $cluster;
        } else {
            $clustered[] = $marker;
        }
    }
    return $clustered;
}
&lt;/pre&gt;

	&lt;p&gt;We can now test clusterer function with array of coordinates.&lt;/p&gt;


&lt;pre&gt;
$markers   = array();
$markers[] = array('id' =&amp;gt; 'marker_1', 
                   'lat' =&amp;gt; 59.441193, 'lon' =&amp;gt; 24.729494);
$markers[] = array('id' =&amp;gt; 'marker_2', 
                   'lat' =&amp;gt; 59.432365, 'lon' =&amp;gt; 24.742992);
$markers[] = array('id' =&amp;gt; 'marker_3', 
                   'lat' =&amp;gt; 59.431602, 'lon' =&amp;gt; 24.757563);
$markers[] = array('id' =&amp;gt; 'marker_4', 
                   'lat' =&amp;gt; 59.437843, 'lon' =&amp;gt; 24.765759);
$markers[] = array('id' =&amp;gt; 'marker_5', 
                   'lat' =&amp;gt; 59.439644, 'lon' =&amp;gt; 24.779041);
$markers[] = array('id' =&amp;gt; 'marker_6', 
                   'lat' =&amp;gt; 59.434776, 'lon' =&amp;gt; 24.756681);

$clustered = cluster($markers, 20, 11);

print_r($clustered);
&lt;/pre&gt;

	&lt;p&gt;If you &lt;a href=&quot;http://www.appelsiini.net/2008/11/clustering.php&quot;&gt;run the code&lt;/a&gt; you can see how marker_3, marker_4 and marker_6 are clustered together. This can better be visualized as map screenshot before and after clustering. Blue marker is a cluster.&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2008/11/3/no_cluster.gif&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;http://www.appelsiini.net/assets/2008/11/3/with_cluster2.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;h3&gt;Real Life Usage?&lt;/h3&gt;


	&lt;p&gt;Obviously making an array of coordinates into a new array of coordinates is not really usefull. However the first  &lt;a href=&quot;http://github.com/tuupola/php_google_maps/tree/master/Google/Maps/Clusterer/Distance.php&quot;&gt;clusterer for Static Maps&lt;/a&gt; I committed to GitHub uses previously described technique. Clustering a static map takes only two extra lines of code. First create a cluster. Then add it to the map object. Rest is taken care automatically.&lt;/p&gt;


&lt;pre&gt;
$clusterer = Google_Maps_Clusterer::create('distance');
$map-&amp;gt;setClusterer($clusterer);
&lt;/pre&gt;

	&lt;p&gt;You can see it in action in &lt;a href=&quot;http://www.appelsiini.net/projects/php_google_maps/cluster.html?center=17.41%2C15.15&amp;amp;#38;infowindow=&amp;amp;#38;zoom=2&quot;&gt;capital cities of the world&lt;/a&gt; map. City locations are parsed from &lt;span class=&quot;caps&quot;&gt;KML&lt;/span&gt; file. Note that in closer zooms locations are slightly off. Coordinates have only two decimals of latitude and longitude.&lt;/p&gt;


	&lt;p&gt;Currently I have demo code only for Static Maps. Serverside clustering for Google Maps &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; will follow soon. Thats a promise. Cross my heart.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.appelsiini.net/">
    <author>
      <name>tuupola</name>
    </author>
    <id>tag:www.appelsiini.net,2008-10-24:1856</id>
    <published>2008-10-24T20:54:00Z</published>
    <updated>2008-11-16T21:19:27Z</updated>
    <category term="google"/>
    <category term="maps"/>
    <category term="php"/>
    <link href="http://www.appelsiini.net/2008/10/simple-zoom-and-pan-controls-with-static-maps" rel="alternate" type="text/html"/>
    <title>Simple Zoom and Pan Controls With Static Maps</title>
<summary type="html">&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2008/10/24/map_bubble.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Most of the code from previous Static Maps experiments is now put into one clean package. Previously I showed you how to work with &lt;a href=&quot;http://www.appelsiini.net/2008/10/simple-static-maps-with-php&quot;&gt;markers and bounds&lt;/a&gt;. Now we go forward and add zoom and pan controls. It takes only few lines of code. If you just started reading the series  check the &lt;a href=&quot;http://www.appelsiini.net/2008/6/google-maps-without-javascript-part-2&quot;&gt;theory how it works&lt;/a&gt;. As a bonus lets add infowindows / bubbles too.&lt;/p&gt;


	&lt;p&gt;Note! Image above is just a screenshot. You can test final result in the &lt;a href=&quot;http://www.appelsiini.net/projects/php_google_maps/controls.html&quot;&gt;demo&lt;/a&gt;.&lt;/p&gt;


	&lt;h3&gt;Create Map and Some Markers&lt;/h3&gt;


	&lt;p&gt;Start by creating new map object and set the size. We also need to give our &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; key. Markers are positioned on map using location object. Location can be latitude and longitude represented by &lt;em&gt;Google_Maps_Coordinate&lt;/em&gt; object. Location can also be map x and y represented by &lt;em&gt;Google_Maps_Point&lt;/em&gt; object.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2008/10/24/map_bubble.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Most of the code from previous Static Maps experiments is now put into one clean package. Previously I showed you how to work with &lt;a href=&quot;http://www.appelsiini.net/2008/10/simple-static-maps-with-php&quot;&gt;markers and bounds&lt;/a&gt;. Now we go forward and add zoom and pan controls. It takes only few lines of code. If you just started reading the series  check the &lt;a href=&quot;http://www.appelsiini.net/2008/6/google-maps-without-javascript-part-2&quot;&gt;theory how it works&lt;/a&gt;. As a bonus lets add infowindows / bubbles too.&lt;/p&gt;


	&lt;p&gt;Note! Image above is just a screenshot. You can test final result in the &lt;a href=&quot;http://www.appelsiini.net/projects/php_google_maps/controls.html&quot;&gt;demo&lt;/a&gt;.&lt;/p&gt;


	&lt;h3&gt;Create Map and Some Markers&lt;/h3&gt;


	&lt;p&gt;Start by creating new map object and set the size. We also need to give our &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; key. Markers are positioned on map using location object. Location can be latitude and longitude represented by &lt;em&gt;Google_Maps_Coordinate&lt;/em&gt; object. Location can also be map x and y represented by &lt;em&gt;Google_Maps_Point&lt;/em&gt; object.&lt;/p&gt;
&lt;p&gt;Because we put markers to map the center is calculated automatically. There is no need to call &lt;em&gt;$map-&amp;gt;setCenter()&lt;/em&gt;. We can also calculate the closest possible zoom with &lt;em&gt;$map-&amp;gt;zoomToFit()&lt;/em&gt;.&lt;/p&gt;


&lt;pre&gt;
require_once 'Google/Maps.php';

$map = Google_Maps::create('static');
$map-&amp;gt;setSize('540x300');
$map-&amp;gt;setKey(API_KEY);

$coord_1 = new Google_Maps_Coordinate('58.378700', '26.731110');
$coord_2 = new Google_Maps_Coordinate('58.379646', '26.764090');

$marker_1 = new Google_Maps_Marker($coord_1);
$marker_2 = new Google_Maps_Marker($coord_2);

$map-&amp;gt;addMarker($marker_1);
$map-&amp;gt;addMarker($marker_2);
$map-&amp;gt;zoomToFit();
&lt;/pre&gt;

	&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2008/10/24/map_markers.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;h3&gt;Add Zoom and Pan Controls&lt;/h3&gt;


	&lt;p&gt;Controls are created using &lt;em&gt;Google_Maps_Control::create()&lt;/em&gt; factory method. After creating a control you must attach it to a map. This alone is not enough. When panning and zooming new map center or zoom value is passed in query string. Last line passes the values from &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; to the map object.&lt;/p&gt;


&lt;pre&gt;
$zoom = Google_Maps_Control::create('zoom');
$map-&amp;gt;addControl($zoom);
$pan = Google_Maps_Control::create('pan');
$map-&amp;gt;addControl($pan);

$map-&amp;gt;setProperties($_GET);
&lt;/pre&gt;

	&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2008/10/24/map_controls.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Note! Image above is just a screenshot. You can test working controls in the &lt;a href=&quot;http://www.appelsiini.net/projects/php_google_maps/controls.html&quot;&gt;demo&lt;/a&gt;.&lt;/p&gt;


	&lt;h3&gt;Add Infowindows / Bubbles&lt;/h3&gt;


	&lt;p&gt;Infowindows (or bubbles as they are often referred) are represented by &lt;em&gt;Google_Maps_Infowindow&lt;/em&gt; object. You can set the content in constructor or using &lt;em&gt;$bubble-&amp;gt;setContent()&lt;/em&gt; method. Bubbles have a marker attached to them. Clicking the marker will open the infowindow. As with all other items you must attach them to map.&lt;/p&gt;


&lt;pre&gt;
$bubble_1 = new Google_Maps_Infowindow('Foo Bar');
$bubble_2 = new Google_Maps_Infowindow('Pler pop');

$bubble_1-&amp;gt;setMarker($marker_1);
$bubble_2-&amp;gt;setMarker($marker_2);

$map-&amp;gt;addInfowindow($bubble_1);
$map-&amp;gt;addInfowindow($bubble_2);
&lt;/pre&gt;

	&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2008/10/24/map_bubble.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Note! Image above is just a screenshot. You can test working infobubbles in the &lt;a href=&quot;http://www.appelsiini.net/projects/php_google_maps/controls.html&quot;&gt;demo&lt;/a&gt;.&lt;/p&gt;


	&lt;h3&gt;Where&#8217;s the Source?&lt;/h3&gt;


	&lt;p&gt;If you want to play around with code you can get from &lt;a href=&quot;http://github.com/tuupola/php_google_maps/tree&quot;&gt;github&lt;/a&gt;. Patches, improvements and suggestion are welcome.&lt;/p&gt;


&lt;pre&gt;git clone git://github.com/tuupola/php_google_maps.git&lt;/pre&gt;
&lt;pre&gt;wget http://github.com/tuupola/php_google_maps/zipball/master&lt;/pre&gt;
          </content>  </entry>
  <entry xml:base="http://www.appelsiini.net/">
    <author>
      <name>tuupola</name>
    </author>
    <id>tag:www.appelsiini.net,2008-10-10:1745</id>
    <published>2008-10-10T15:46:00Z</published>
    <updated>2009-03-13T10:17:57Z</updated>
    <category term="google"/>
    <category term="maps"/>
    <category term="php"/>
    <link href="http://www.appelsiini.net/2008/10/simple-static-maps-with-php" rel="alternate" type="text/html"/>
    <title>Simple Static Maps With PHP</title>
<summary type="html">&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2008/10/10/staticmap.gif&quot; alt=&quot;&quot; /&gt; Lately I have been playing with Google Static Maps &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; a lot. Writing the same things again and again is tedious job. I decided to put the code together as one clean extendable package. Writing object oriented interface for generating &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; is trivial. Real meat is having working &lt;a href=&quot;http://www.appelsiini.net/projects/php_google_maps/controls.html&quot;&gt;zoom and pan controls&lt;/a&gt; on static map &lt;del&gt;with just 9 lines of code&lt;/del&gt; (demo now includes also clickable markers and infowindows).&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://github.com/tuupola/php_google_maps/tree/master&quot;&gt;Code&lt;/a&gt; is still alpha quality. &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; might change any time. But here is a quick walkthrough of current features. We will build the map you see above step by step.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2008/10/10/staticmap.gif&quot; alt=&quot;&quot; /&gt; Lately I have been playing with Google Static Maps &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; a lot. Writing the same things again and again is tedious job. I decided to put the code together as one clean extendable package. Writing object oriented interface for generating &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; is trivial. Real meat is having working &lt;a href=&quot;http://www.appelsiini.net/projects/php_google_maps/controls.html&quot;&gt;zoom and pan controls&lt;/a&gt; on static map &lt;del&gt;with just 9 lines of code&lt;/del&gt; (demo now includes also clickable markers and infowindows).&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://github.com/tuupola/php_google_maps/tree/master&quot;&gt;Code&lt;/a&gt; is still alpha quality. &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; might change any time. But here is a quick walkthrough of current features. We will build the map you see above step by step.&lt;/p&gt;
&lt;h3&gt;Create a Map Object&lt;/h3&gt;


	&lt;p&gt;Map object is created using &lt;i&gt;Google_Maps::create(&#8216;static&#8217;)&lt;/i&gt; factory method.  If no markers are set you also need to set the center of the map.&lt;/p&gt;


&lt;pre&gt;require_once 'Google/Maps.php';

$map = Google_Maps::create('static');

$map-&amp;gt;setSize('540x300');
$map-&amp;gt;setCenter(new Google_Maps_Coordinate('58.368488', '26.768908'));
$map-&amp;gt;setZoom(8);
$map-&amp;gt;setKey(API_KEY);&lt;/pre&gt;
    &lt;/p&gt;

    &lt;img src=&quot;http://maps.google.com/staticmap?center=58.368488%2C26.768908&amp;amp;#38;zoom=8&amp;amp;#38;markers=&amp;amp;#38;size=540x300&amp;amp;#38;key=ABQIAAAASWfI7GkTRVrz1brU7GwV2BRb4tuXOrVDWXaYNDB1tYm76RuEyxQuEAfETfgIzoUG0VXo0yBFqfuU2g&quot; height=&quot;300&quot; alt=&quot;&quot; width=&quot;540&quot; /&gt;
&lt;br /&gt;&lt;br /&gt;

	&lt;h3&gt;Add some markers&lt;/h3&gt;


	&lt;p&gt;Location on map can be in two ways. Latitude and longitude represented by &lt;i&gt;Google_Maps_Coordinate&lt;/i&gt; object. Or pixel x and pixel y location represented by &lt;i&gt;Google_Maps_Point&lt;/i&gt; object. You can use both when creating a marker.&lt;/p&gt;


&lt;pre&gt;$coord_1 = new Google_Maps_Coordinate('58.378700', '26.731110');
$coord_2 = new Google_Maps_Coordinate('58.368488', '26.768908');
$coord_3 = new Google_Maps_Coordinate('58.268488', '26.768908');

$marker_1 = new Google_Maps_Marker($coord_1);
$marker_2 = new Google_Maps_Marker($coord_2);
$marker_3 = new Google_Maps_Marker($coord_3);

$marker_1-&amp;gt;setColor('green');
$marker_2-&amp;gt;setColor('blue');
$marker_3-&amp;gt;setColor('orange');

$map-&amp;gt;setMarkers(array($marker_1, $marker_2, $marker_3));&lt;/pre&gt;

	&lt;p&gt;&lt;img src=&quot;http://maps.google.com/staticmap?center=58.368488%2C26.768908&amp;amp;#38;zoom=8&amp;amp;#38;markers=58.378700%2C26.731110%2Cgreen%7C58.368488%2C26.768908%2Cblue%7C58.268488%2C26.768908%2Corange%7C&amp;amp;#38;size=540x300&amp;amp;#38;key=ABQIAAAASWfI7GkTRVrz1brU7GwV2BRb4tuXOrVDWXaYNDB1tYm76RuEyxQuEAfETfgIzoUG0VXo0yBFqfuU2g&quot; height=&quot;300&quot; alt=&quot;&quot; width=&quot;540&quot; /&gt;
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;


	&lt;h3&gt;Automatically Calculate Zoom and Center&lt;/h3&gt;


	&lt;p&gt;Google Static Maps &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; can automatically calculate zoom and center for you. However there is no way to know what zoom level it chose. If you need to know automatically calculated zoom and center use &lt;i&gt;$map-&amp;gt;zoomToFit()&lt;/i&gt; method.&lt;/p&gt;


	&lt;p&gt;Here we also add new marker using pixel coordinates. Note that we also clear the center of the map we set in the beginning. This allows map to recenter the map according to markers on the map.&lt;/p&gt;


&lt;pre&gt;$point_1  = new Google_Maps_Point('308107197', '160958681');
$marker_4 = new Google_Maps_Marker($point_1);
$map-&amp;gt;setCenter(false);
$map-&amp;gt;addMarker($marker_4);
$map-&amp;gt;zoomToFit();&lt;/pre&gt;

	&lt;p&gt;&lt;img src=&quot;http://maps.google.com/staticmap?center=58.319541032213%2C26.717725334168&amp;amp;#38;zoom=10&amp;amp;#38;markers=58.378700%2C26.731110%2Cgreen%7C58.368488%2C26.768908%2Cblue%7C58.268488%2C26.768908%2Corange%7C58.262488128851%2C26.601975336671%2C%7C&amp;amp;#38;size=540x300&amp;amp;#38;key=ABQIAAAASWfI7GkTRVrz1brU7GwV2BRb4tuXOrVDWXaYNDB1tYm76RuEyxQuEAfETfgIzoUG0VXo0yBFqfuU2g&quot; height=&quot;300&quot; alt=&quot;&quot; width=&quot;540&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;


	&lt;h3&gt;Show Marker Bounds&lt;/h3&gt;


	&lt;p&gt;Sometimes you need to be able to visually see bounding box where all the markers fit in.&lt;/p&gt;


&lt;pre&gt;$map-&amp;gt;showMarkerBounds();&lt;/pre&gt;

	&lt;p&gt;&lt;img src=&quot;http://maps.google.com/staticmap?center=58.319541032213%2C26.717725334168&amp;amp;#38;zoom=10&amp;amp;#38;markers=58.378700%2C26.731110%2Cgreen%7C58.368488%2C26.768908%2Cblue%7C58.268488%2C26.768908%2Corange%7C58.262488128851%2C26.601975336671%2C%7C&amp;amp;#38;path=58.378700%2C26.601975336671%7C58.378700%2C26.768908%7C58.262488128851%2C26.768908%7C58.262488128851%2C26.601975336671%7C58.378700%2C26.601975336671%7C&amp;amp;#38;size=540x300&amp;amp;#38;key=ABQIAAAASWfI7GkTRVrz1brU7GwV2BRb4tuXOrVDWXaYNDB1tYm76RuEyxQuEAfETfgIzoUG0VXo0yBFqfuU2g&quot; height=&quot;300&quot; alt=&quot;&quot; width=&quot;540&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;


	&lt;h3&gt;Show Map Bounds at Chosen Zoom Level&lt;/h3&gt;


	&lt;p&gt;You can also calculate and show map bounds at any zoom level. Example below displays map bounds at zoom level 8. Map itself is at zoom level 7.&lt;/p&gt;


&lt;pre&gt;$map-&amp;gt;setZoom(7);
$map_bounds = $map-&amp;gt;getBounds(8);
$map-&amp;gt;setPath($map_bounds-&amp;gt;getPath());&lt;/pre&gt;

	&lt;p&gt;&lt;img src=&quot;http://maps.google.com/staticmap?center=58.319541032213%2C26.717725334168&amp;amp;#38;zoom=7&amp;amp;#38;markers=58.378700%2C26.731110%2Cgreen%7C58.368488%2C26.768908%2Cblue%7C58.268488%2C26.768908%2Corange%7C58.262488128851%2C26.601975336671%2C%7C&amp;amp;#38;path=58.749635911828%2C25.234571099281%7C58.749635911828%2C28.200879693031%7C57.884150180108%2C28.200879693031%7C57.884150180108%2C25.234571099281%7C58.749635911828%2C25.234571099281%7C&amp;amp;#38;size=540x300&amp;amp;#38;key=ABQIAAAASWfI7GkTRVrz1brU7GwV2BRb4tuXOrVDWXaYNDB1tYm76RuEyxQuEAfETfgIzoUG0VXo0yBFqfuU2g&quot; height=&quot;300&quot; alt=&quot;&quot; width=&quot;540&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;


	&lt;h3&gt;Where&#8217;s the Source?&lt;/h3&gt;


	&lt;p&gt;If you want to play around with code you can get from &lt;a href=&quot;http://github.com/tuupola/php_google_maps/tree&quot;&gt;github&lt;/a&gt;. Patches, improvements and suggestion are welcome.&lt;/p&gt;


&lt;pre&gt;git clone git://github.com/tuupola/php_google_maps.git&lt;/pre&gt;
&lt;pre&gt;wget http://github.com/tuupola/php_google_maps/zipball/master&lt;/pre&gt;

	&lt;p&gt;Related entries: &lt;a href=&quot;http://www.appelsiini.net/2008/9/infowindows-with-google-static-maps&quot;&gt;Infowindows With Google Static Maps&lt;/a&gt;, &lt;a href=&quot;http://www.appelsiini.net/2008/6/clickable-markers-with-google-static-maps&quot;&gt;Clickable Markers With Google Static Maps&lt;/a&gt;.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.appelsiini.net/">
    <author>
      <name>tuupola</name>
    </author>
    <id>tag:www.appelsiini.net,2008-10-08:1740</id>
    <published>2008-10-08T15:09:00Z</published>
    <updated>2008-11-16T21:20:03Z</updated>
    <category term="mephisto"/>
    <category term="rails"/>
    <link href="http://www.appelsiini.net/2008/10/mephisto-sitemap-plugin-with-engines-support" rel="alternate" type="text/html"/>
    <title>Mephisto Sitemap Plugin With Engines Support</title>
<content type="html">
            &lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2008/10/8/mephisto_admin.png&quot; alt=&quot;&quot; /&gt; I made quick fix to &lt;a href=&quot;http://www.appelsiini.net/projects/mephisto_sitemap&quot;&gt;Mephisto Sitemap&lt;/a&gt; plugin. Now it works with lates Mephisto 0.8 (Drax). All old plugins got broken when Mephisto changed to &lt;a href=&quot;http://rails-engines.org/&quot;&gt;Rails Engines&lt;/a&gt; based plugin system.&lt;/p&gt;


	&lt;p&gt;Install by issuing the following command in your Mephisto root.&lt;/p&gt;


&lt;pre&gt;
script/plugin install 
http://svn.appelsiini.net/svn/rails/plugins/mephisto_sitemap/
&lt;/pre&gt;

	&lt;p&gt;After installing remember to restart you WEBrick or Mongrel.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.appelsiini.net/">
    <author>
      <name>tuupola</name>
    </author>
    <id>tag:www.appelsiini.net,2008-10-08:1739</id>
    <published>2008-10-08T10:31:00Z</published>
    <updated>2008-10-26T00:20:18Z</updated>
    <link href="http://www.appelsiini.net/2008/10/why-i-chose-slicehost-over-media-temple" rel="alternate" type="text/html"/>
    <title>Why I Chose Slicehost over Media Temple</title>
<summary type="html">&lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2008/10/7/slicehost.jpg&quot; alt=&quot;&quot; /&gt; I have been running my own hardware since early 90&#8217;s. Hardware has always been produced by &lt;a href=&quot;http://www.sun.com/&quot;&gt;Sun Microsystems&lt;/a&gt;. Yes, I am a Sun fanboy. Times change and I am forced to retire my old hardware. So I went for shopping for decent &lt;span class=&quot;caps&quot;&gt;VPS&lt;/span&gt;. Tried Media Temple first. Gandi was still invitation only. In the end chose Slicehost. Here are the reasons why.&lt;/p&gt;


	&lt;h3&gt;Download Speed to Europe&lt;/h3&gt;


	&lt;p&gt;I do have a small problem with having my hosting physically located in Northern America. I was worried of getting low download speed to Europe. I tested this from several hosts located in Finland and Estonia. Slicehost was always faster than Media Temple.&lt;/p&gt;</summary><content type="html">
            &lt;p&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2008/10/7/slicehost.jpg&quot; alt=&quot;&quot; /&gt; I have been running my own hardware since early 90&#8217;s. Hardware has always been produced by &lt;a href=&quot;http://www.sun.com/&quot;&gt;Sun Microsystems&lt;/a&gt;. Yes, I am a Sun fanboy. Times change and I am forced to retire my old hardware. So I went for shopping for decent &lt;span class=&quot;caps&quot;&gt;VPS&lt;/span&gt;. Tried Media Temple first. Gandi was still invitation only. In the end chose Slicehost. Here are the reasons why.&lt;/p&gt;


	&lt;h3&gt;Download Speed to Europe&lt;/h3&gt;


	&lt;p&gt;I do have a small problem with having my hosting physically located in Northern America. I was worried of getting low download speed to Europe. I tested this from several hosts located in Finland and Estonia. Slicehost was always faster than Media Temple.&lt;/p&gt;
&lt;p&gt;Slicehost usually gave between 700-800 KB/s. Not bad. Same speed I usually get from local shared hosting.&lt;/p&gt;


&lt;pre&gt;
$ wget http://sh.appelsiini.net/somefile.mov
...
Length: 17140878 (16M) [video/quicktime]
Saving to: `somefile.mov'

100%[===================================&amp;gt;] 17,140,878  1019K/s   in 22s    

21:41:45 (758 KB/s) - `somefile.mov' saved [17140878/17140878]
&lt;/pre&gt;

	&lt;p&gt;Media Temple delivered between 350-450 KB/s. Still OK but I prefer double speed when I can get it.&lt;/p&gt;


&lt;pre&gt;
$ wget http://mt.appelsiini.net/somefile.mov
...
Length: 17140878 (16M) [video/quicktime]
Saving to: `somefile.mov.1'

100%[===================================&amp;gt;] 17,140,878   364K/s   in 47s    

21:40:22 (354 KB/s) - `somefile.mov.1' saved [17140878/17140878]
&lt;/pre&gt;

	&lt;h3&gt;Ping Times&lt;/h3&gt;


	&lt;p&gt;I am old school. I prefer working on shell. Yes color is green over black and I even use tcsh. I said it. Old school. Anyway, working on shell requires decent ping times. Otherwise my brain will have nervous breakdown if there is a delay between keypress and character appearing on screen.&lt;/p&gt;


	&lt;p&gt;Again Slicehost was bit better.&lt;/p&gt;


&lt;pre&gt;
--- sh.appelsiini.net ping statistics ---
30 packets transmitted, 30 received, 0% packet loss, time 29008ms
rtt min/avg/max/mdev = 132.676/133.293/136.268/0.643 ms
&lt;/pre&gt;

	&lt;p&gt;Media Temple was not bad either. Still difference was big enough to make shell window feel bit more sluggish.&lt;/p&gt;


&lt;pre&gt;
--- mt.appelsiini.net ping statistics ---
30 packets transmitted, 30 received, 0% packet loss, time 29018ms
rtt min/avg/max/mdev = 173.426/175.430/178.108/1.365 ms
&lt;/pre&gt;

	&lt;h3&gt;Plesk is Horrible&lt;/h3&gt;


	&lt;p&gt;I already mentioned preferring the shell. My biggest problem with Media Temple was &lt;a href=&quot;http://www.parallels.com/plesk/&quot;&gt;Plesk&lt;/a&gt;. It is horrible. Slow to use. Makes too many decisions by itself. You do not really know what is happening. I understand it might work for other people. It just did not work for me.&lt;/p&gt;


	&lt;h3&gt;Which one Should I Choose?&lt;/h3&gt;


	&lt;p&gt;If you consider yourself developer type choose &lt;a href=&quot;http://www.slicehost.com/&quot;&gt;Slicehost&lt;/a&gt;. If you consider yourself designer you might be better off with &lt;a href=&quot;http://www.mediatemple.com/&quot;&gt;Media Temple&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;caps&quot;&gt;UPDATE&lt;/span&gt;:&lt;/strong&gt; Media Temple made a test setup for me to try a virtual server located in their East Coast datacenter. Both ping times and download speeds were much better. Media Temple also noted they developing are developing similar barebone &lt;span class=&quot;caps&quot;&gt;VPS&lt;/span&gt; service as SliceHost is providing. It will be geared towards developers.&lt;/p&gt;


&lt;pre&gt;
$ wget http://70.32.72.30/somefile.iso
...
Length: 716881920 (684M) [application/octet-stream]
Saving to: `somefile.iso'

100%[===================================&amp;gt;] 716,881,920  580K/s   in 20m 10s

17:18:31 (579 KB/s) - `solaris.iso' saved [716881920/716881920]
&lt;/pre&gt;

&lt;pre&gt;
--- 70.32.72.30 ping statistics ---
30 packets transmitted, 30 received, 0% packet loss, time 29009ms
rtt min/avg/max/mdev = 106.092/106.273/106.702/0.212 ms
&lt;/pre&gt;
          </content>  </entry>
  <entry xml:base="http://www.appelsiini.net/">
    <author>
      <name>tuupola</name>
    </author>
    <id>tag:www.appelsiini.net,2008-09-23:1703</id>
    <published>2008-09-23T19:20:00Z</published>
    <updated>2008-09-23T19:20:41Z</updated>
    <category term="latvia"/>
    <category term="work"/>
    <link href="http://www.appelsiini.net/2008/9/golden-hammer-2008" rel="alternate" type="text/html"/>
    <title>Golden Hammer 2008</title>
<content type="html">
            &lt;p&gt;&lt;a href=&quot;http://www.hammer.lv/&quot;&gt;&lt;img src=&quot;http://www.appelsiini.net/assets/2008/9/23/hammer.jpg&quot; alt=&quot;&quot; /&gt;&lt;/a&gt; Today I arrived to sunny Riga to attend 9th &lt;a href=&quot;http://www.hammer.lv/&quot;&gt;Golden Hammer&lt;/a&gt; festival. I was invited to be &lt;a href=&quot;http://www.hammer.lv/?id=143&quot;&gt;Head of Digital Media Jury&lt;/a&gt;. Something I am really looking forward to.&lt;/p&gt;


	&lt;p&gt;As usual organization of all things has been top notch. Baltic people are absolutely great at organizing events. If any of you readers are here this week drop me a line or tweet. On thursday there will be &lt;a href=&quot;http://www.badad.lv/&quot;&gt;BadAd party&lt;/a&gt; which is definitely worth visiting too.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://www.appelsiini.net/">
    <author>
      <name>tuupola</name>
    </author>
    <id>tag:www.appelsiini.net,2008-09-19:1685</id>
    <published>2008-09-19T10:07:00Z</published>
    <updated>2008-09-19T10:08:47Z</updated>
    <link href="http://www.appelsiini.net/2008/9/between-hosts" rel="alternate" type="text/html"/>
    <title>Between Hosts</title>
<content type="html">
            &lt;p&gt;I am in process of moving to a new host. If you see this you read content from the new server. Some things (especially &lt;span class=&quot;caps&quot;&gt;WTF&lt;/span&gt;-8) might be broken. Would be great if you leave a comment when you find a broken demo or page.&lt;/p&gt;
          </content>  </entry>
</feed>
