<?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: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-5308531346925315578</id><updated>2011-09-08T17:03:23.762+01:00</updated><category term='google apis'/><category term='google wave'/><category term='google map'/><category term='css'/><category term='MySQL'/><category term='blogger api'/><category term='moose'/><category term='google earth'/><category term='CakePHP 1.2'/><category term='html'/><category term='perl'/><category term='embed waves'/><category term='AuthSub'/><category term='google'/><category term='misc'/><title type='text'>thasha.in.wonderland</title><subtitle type='html'>… of Internet</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>25</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-3261204753643170416</id><published>2011-07-11T00:37:00.001+01:00</published><updated>2011-07-11T00:37:11.665+01:00</updated><title type='text'>Flashback – Optimus Alive 2011</title><content type='html'>&lt;p&gt;Hello all! I have been gone for a long time, but not without a reason. I had (and still have) a lot of new challenges.&lt;/p&gt;  &lt;p&gt;The most recent is an Android application for a very awesome action called &lt;strong&gt;Flashback&lt;/strong&gt; which took place during &lt;strong&gt;Optimus Alive Festival&lt;/strong&gt; in Lisbon (Alges).&lt;/p&gt;  &lt;p&gt;The idea is simple but great. We have 32 Android mobiles running (my) special app.&amp;#160; They all are mounted on a round stage. People willing to have taken a picture pose in the center. Next, at the right moment, all mobiles take a picture at once. All pictures are send to a computer behind the stage where our small post-production team puts them together . In effect we have 360 degrees matrix effect movie – complete 3D experience that may be shared later will friends using social networks. &lt;/p&gt;  &lt;p&gt;Below some pictures and links to information about the event.&lt;/p&gt;  &lt;p&gt;Promotional video for &lt;strong&gt;Flashback &lt;/strong&gt;event: &lt;a title="http://flashback.optimus.pt/home.php" href="http://flashback.optimus.pt/home.php"&gt;http://flashback.optimus.pt/home.php&lt;/a&gt;&lt;/p&gt;  &lt;p align="center"&gt;&lt;a href="http://lh4.ggpht.com/-JLSIBWwzkuE/Tho3mNIhb1I/AAAAAAAAAf4/JtE6trCY250/s1600-h/flashback_optimus_alive%25255B2%25255D.jpg"&gt;&lt;img style="display: block; float: none; margin-left: auto; margin-right: auto" title="flashback_optimus_alive" alt="flashback_optimus_alive" src="http://lh3.ggpht.com/-qWk7Bb2dvGk/Tho3m1zd1FI/AAAAAAAAAf8/_3pi4h77k0g/flashback_optimus_alive_thumb.jpg?imgmax=800" width="160" height="240" /&gt;&lt;/a&gt;People really enjoy this new experience.&amp;#160; &lt;/p&gt;  &lt;p align="center"&gt;&lt;a href="http://lh5.ggpht.com/--2FVHTrCYoE/Tho3nc0x_GI/AAAAAAAAAgA/5m3_eXgSLs0/s1600-h/flashback_stage%25255B2%25255D.jpg"&gt;&lt;img style="display: block; float: none; margin-left: auto; margin-right: auto" title="flashback_stage" alt="flashback_stage" src="http://lh6.ggpht.com/-eOUMDYIXzW8/Tho3oHMPtwI/AAAAAAAAAgE/tly1WlgOcSw/flashback_stage_thumb.jpg?imgmax=800" width="160" height="240" /&gt;&lt;/a&gt;Our stage just opposite to the main stage...&amp;#160; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/-tSOUO_09_Ms/Tho3o30g0LI/AAAAAAAAAgI/hx2cwtqTOek/s1600-h/flashback_foofighters%25255B2%25255D.jpg"&gt;&lt;img style="display: block; float: none; margin-left: auto; margin-right: auto" title="flashback_foofighters" alt="flashback_foofighters" src="http://lh5.ggpht.com/-aTeiEBzcxxA/Tho3pvjgKYI/AAAAAAAAAgM/IA2L2MJnsN0/flashback_foofighters_thumb.jpg?imgmax=800" width="240" height="169" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="center"&gt;…and on the main stage stars like Foo Fighters :)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-3261204753643170416?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/3261204753643170416/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2011/07/flashback-optimus-alive-2011.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/3261204753643170416'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/3261204753643170416'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2011/07/flashback-optimus-alive-2011.html' title='Flashback – Optimus Alive 2011'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/-qWk7Bb2dvGk/Tho3m1zd1FI/AAAAAAAAAf8/_3pi4h77k0g/s72-c/flashback_optimus_alive_thumb.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-6796437053526082299</id><published>2011-02-03T00:11:00.001Z</published><updated>2011-02-03T00:11:10.614Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><category scheme='http://www.blogger.com/atom/ns#' term='google'/><title type='text'>Great initiative for all art lovers.</title><content type='html'>&lt;p&gt;For all programmers (and not only) who already glued to their chairs. Now you don’t need to force yourself to look away from your computer screen. 17 grates museums from around the world are in front of you.    &lt;br /&gt;&lt;a title="Google Art Project" href="http://www.googleartproject.com/" target="_blank"&gt;http://www.googleartproject.com/&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-6796437053526082299?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/6796437053526082299/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2011/02/great-initiative-for-all-art-lovers.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/6796437053526082299'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/6796437053526082299'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2011/02/great-initiative-for-all-art-lovers.html' title='Great initiative for all art lovers.'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-7417224020795105400</id><published>2011-02-01T23:16:00.001Z</published><updated>2011-02-01T23:17:49.369Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='moose'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Introduction to Moose</title><content type='html'>&lt;p&gt;Now I’m Perl programmer :) and some time ago I was asked to prepare short intro to Moose.    &lt;br /&gt;Since Perl is only a bit object-oriented language, Moose enables object oriented features similar to those existing in languages like C++ or Java.     &lt;br /&gt;I’m also quite a new to this topic, so the intro is really simple. &lt;a href="http://thashawonderland.appspot.com/files/moose/code.tar.gz"&gt;Here&lt;/a&gt; are some code snippets that I used for this presentation.&lt;/p&gt;  &lt;p&gt;(BTW: for those who are new to Perl I have a nice link: &lt;a href="http://www.netalive.org/tinkering/serious-perl/" rel="nofollow"&gt;http://www.netalive.org/tinkering/serious-perl/&lt;/a&gt;).&lt;/p&gt;  &lt;div style="width: 425px" id="__ss_6776248"&gt;&lt;strong style="margin: 12px 0px 4px; display: block"&gt;&lt;a title="Introduction to Moose" href="http://www.slideshare.net/thashaa/introduction-to-moose-6776248"&gt;Introduction to Moose&lt;/a&gt;&lt;/strong&gt;&lt;object id="__sse6776248" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=slides-110201095020-phpapp01&amp;amp;stripped_title=introduction-to-moose-6776248&amp;amp;userName=thashaa" /&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="allowScriptAccess" value="always" /&gt;&lt;embed name="__sse6776248" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=slides-110201095020-phpapp01&amp;amp;stripped_title=introduction-to-moose-6776248&amp;amp;userName=thashaa" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;    &lt;div style="padding-bottom: 12px; padding-left: 0px; padding-right: 0px; padding-top: 5px"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/thashaa"&gt;thashaa&lt;/a&gt;.&lt;/div&gt; &lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-7417224020795105400?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/7417224020795105400/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2011/02/introduction-to-moose.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/7417224020795105400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/7417224020795105400'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2011/02/introduction-to-moose.html' title='Introduction to Moose'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-717788106305062109</id><published>2011-01-25T22:40:00.001Z</published><updated>2011-01-25T22:40:33.621Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL'/><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='google apis'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>New Year's Promise: become a better web developer.</title><content type='html'>&lt;p&gt;Every January there is a time to do a new year’s promise to yourself. One&amp;#160; may want to loss some weight somebody else to gain some, but there are still some crazy people who want to code better. Code better for them self, for everyone for better web.    &lt;br /&gt;Still, new year’s promises are known as difficult to keep. If you are one of those, who always find excuses I will deprive you of one. Here is the list of the best online web development courses - all for free and at any time you want.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;IBM developerWorks     &lt;br /&gt;&lt;/strong&gt;Great library of technical content (BTW promoting IBM products).    &lt;br /&gt;Web development sections covers topics like Ajax, JavaScript, Web 2.0 and cutting-edge technologies like Cloud Computing and HTML5.    &lt;br /&gt;Besides resources IBM hosts developers community.    &lt;br /&gt;&lt;a title="IBM developerWorks" href="http://www.ibm.com/developerworks/web/" target="_blank"&gt;http://www.ibm.com/developerworks/web/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Yahoo Developer Network     &lt;br /&gt;&lt;/strong&gt;Another good place for those who are hunting for web development knowledge. Library includes resources about Design Pattern, Flash, Java, PHP, Python, Ruby, JavaScript, .Net and&amp;#160; Flash. Besides there is a good documentation for great Yahoo APIs.    &lt;br /&gt;&lt;a title="Yahoo Developer Network" href="http://developer.yahoo.com" target="_blank"&gt;http://developer.yahoo.com&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;A list apart &lt;/strong&gt;- For people who makes websites...    &lt;br /&gt;is the slogan of this site. In the Code section there is a bunch of articles related to web development like CSS, HTML and HTML5 and also server-side technologies. But that is not all what it offers. Worth to check out.    &lt;br /&gt;&lt;a title="A list apart" href="http://www.alistapart.com/topics/code/" rel="nofollow" target="_blank"&gt;http://www.alistapart.com/topics/code/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Google Code University     &lt;br /&gt;&lt;/strong&gt;Google is known from taking part in all possible Internet initiatives. This time it offers good and still growing course library. Among other things - HTML5 and security of internet applications.    &lt;br /&gt;&lt;a title="Google Code University" href="http://code.google.com/edu/" target="_blank"&gt;http://code.google.com/edu/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Dev.Opera     &lt;br /&gt;&lt;/strong&gt;Library full of articles related to different Opera technologies and general topics of web development like HTML5, CSS, JavaScript.    &lt;br /&gt;&lt;a title="Dev.Opera" href="http://dev.opera.com" target="_blank"&gt;http://dev.opera.com&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;W3Schools     &lt;br /&gt;&lt;/strong&gt;is, and always was, a great resource for studying many web technologies covering most XML - based technologies, JavaScript, web-services and server-side programming like PHP, MySQL and .Net.&amp;#160; All tutorials are complete, have links to documentations and code playground.    &lt;br /&gt;&lt;a title="W3Schools" href="http://www.w3schools.com/" target="_blank"&gt;http://www.w3schools.com/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Webmonkey   &lt;br /&gt;Tutorials on Webmonkey are another great database of knowledge. It will help you to learn JavaScript and JavaScript frameworks, CSS and HTML 5,&amp;#160; as well as basic web server configuration and web design. In general - everything you may need in your daily life.    &lt;br /&gt;&lt;a title="Webmonkey" href="http://www.webmonkey.com/tutorials/" target="_blank"&gt;http://www.webmonkey.com/tutorials/&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-717788106305062109?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/717788106305062109/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2011/01/new-year-promise-become-better-web.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/717788106305062109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/717788106305062109'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2011/01/new-year-promise-become-better-web.html' title='New Year&amp;#39;s Promise: become a better web developer.'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-6610243971665559502</id><published>2010-09-20T11:39:00.000+01:00</published><updated>2010-11-24T20:56:41.874Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL'/><title type='text'>MySQL part 3: optimization hints.</title><content type='html'>&lt;p&gt;Database performance is very important for achieving maximal ergonomics of the website. Everyone knows that one of the most important usability condition is the response time. Everyone knows also that the database may be the bottleneck. In the worst case it may even cause inaccessibility of the website. &lt;/p&gt;  &lt;p&gt;Let’s have a closer look at this problem.&lt;/p&gt;  &lt;p&gt;I used again my sample &lt;em&gt;&lt;a href="http://thasha-in-wonderland.blogspot.com/2010/09/mysql-part-1-joins-in-nutshell.html" target="_blank"&gt;The Lost&lt;/a&gt;&lt;/em&gt; database but with greater number of records (the table &lt;em&gt;pictures &lt;/em&gt;has now 1 000 000 records and the table &lt;em&gt;people_pictures&lt;/em&gt; has 3 000 000 records).&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_C4LysrTfKdY/TJc6Nah-DVI/AAAAAAAAAdA/0WPcEvIJ6mA/s1600-h/lost-basic%5B4%5D.png"&gt;&lt;img style="display: inline" title="lost-basic" alt="lost-basic" src="http://lh5.ggpht.com/_C4LysrTfKdY/TJc6N9deEhI/AAAAAAAAAdE/pcoEtuxV9JU/lost-basic_thumb%5B2%5D.png?imgmax=800" width="466" height="271" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;The size of the database is now 118,3 Mb.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://thashawonderland.appspot.com/files/php/misc/fillin.php" target="_blank"&gt;Here&lt;/a&gt; you can find a simple PHP script to generate such number of records. &lt;/p&gt;  &lt;p&gt;Imagine that now we are about to create a simple website for this collection. The typical queries we could use are as follow:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Query 1&lt;/strong&gt;: Show all types and the number of pictures of each type. (We want to use this for creating a side menu where the type’s names with the links and the number of pictures will be given in brackets for every type.)&lt;/p&gt;  &lt;pre class="brush: sql"&gt;select types.name, count(pictures.id) from types, pictures where pictures.type_id=types.id group by types.name;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Query 2&lt;/strong&gt;: Show all characters with the number of pictures in which they are tagged. (This query can be also used for another type of side menu.)&lt;/p&gt;

&lt;pre class="brush: sql"&gt;select people.name, count(people_pictures.id) from people join people_pictures on (people.id=people_pictures.people_id) group by people.name;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Query 3&lt;/strong&gt;: Show 20 newest pictures (the creation date counts) with all characters tagged in every picture (it can be the main element on the website).&lt;/p&gt;

&lt;pre class="brush: sql"&gt;select filename, group_concat(name) from people_pictures join pictures on (people_pictures.picture_id=pictures.id) join people on (people_pictures.people_id=people.id) group by filename order by date limit 1,20;&lt;/pre&gt;

&lt;p&gt;These queries are very simple but they perform very bad. (On my computer: query1 – 22s, query2 – 84s and query3 reaches the time-out – 240s).&lt;/p&gt;

&lt;h4&gt;Design makes difference&lt;/h4&gt;

&lt;p&gt;At the beginning let’s have a look at the types we use. I purposely created&amp;#160; the first version of database with the “default” types and sizes. Most of them we can substitute with something less heavy. For example: for the tables &lt;em&gt;types&lt;/em&gt;, &lt;em&gt;places &lt;/em&gt;and &lt;em&gt;people&lt;/em&gt; the &lt;em&gt;id&lt;/em&gt; column will rather not have more than 100 rows, so we can use TINYINT instead of INT. We can also limit all the columns &lt;em&gt;name &lt;/em&gt;to 25 characters. All changes in the pictures below:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_C4LysrTfKdY/TJc6OUMAvEI/AAAAAAAAAdI/jmmBCvtMJq8/s1600-h/fistopt%5B3%5D.png"&gt;&lt;img style="display: inline" title="fistopt" alt="fistopt" src="http://lh6.ggpht.com/_C4LysrTfKdY/TJc6O8vbZjI/AAAAAAAAAdM/T8dIbcUSvJI/fistopt_thumb%5B1%5D.png?imgmax=800" width="333" height="271" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;This way we already earn some time for first two queries. Query1 takes now 2s and Query2 26s. Query 3 still reaches the time limit.&lt;/p&gt;

&lt;p&gt;More information about MySQL data types is &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/data-types.html" target="_blank"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;Indexes&lt;/h4&gt;

&lt;p&gt;Indexes should be created carefully. In most cases, added correctly, may dramatically speed up the queries. Generally speaking we should create indexes on these columns that we use for JOINs and clauses WHERE, ORDER BY and GROUP BY.&lt;/p&gt;

&lt;p&gt;Query 3 joins tables &lt;em&gt;people_pictures&lt;/em&gt; with &lt;em&gt;people &lt;/em&gt;and &lt;em&gt;pictures&lt;/em&gt; (relation many-to-many). It seems reasonable to create indexes on columns &lt;em&gt;people_id&lt;/em&gt; and &lt;em&gt;picture_id&lt;/em&gt; in &lt;em&gt;people_pictures &lt;/em&gt;table. The result set is grouped by &lt;em&gt;pictures.filename&lt;/em&gt; and ordered by &lt;em&gt;pictures.date&lt;/em&gt;. We can create more two indexes on these columns. Such modification decrease the execution time to 196 s.&lt;/p&gt;

&lt;p&gt;In some cases, indexes may provoke increase of execution time. Let’s have a look at Query 1. It uses column &lt;em&gt;pictures.type_id&lt;/em&gt; to join pictures with their types. However if we create index on &lt;em&gt;pictures.type_id&lt;/em&gt; we notice that the execution time for this query increases to 13s .&lt;/p&gt;

&lt;p&gt;Using indexes for joining dictionary-like tables produces overhead. The index may take more space that the actual table data. In such cases it is faster to read sequentially from table, because this minimizes disk seeks (especially when the dictionary table is short).&lt;/p&gt;

&lt;p&gt;For Query 1 we can just delete the index from &lt;em&gt;pictures.type_id.&lt;/em&gt; But what happened when we use the same index in few queries and it increase the execution time only for some of them? Fortunately there is an easy solution. We can modify the query by adding &lt;strong&gt;ignore index&lt;/strong&gt; hint.&lt;/p&gt;

&lt;p&gt;The final results of this optimization phase are Query1: 2s, Query 2: 20s and Query3: 196s - still too much.&lt;/p&gt;

&lt;p&gt;This is what we can achieve optimizing on spec. The better way is to look closer at every particular query.&lt;/p&gt;

&lt;p&gt;Some useful links:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html" target="_blank"&gt;How MySQL Uses Indexes&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://hackmysql.com/case4" target="_blank"&gt;How To Index For Joins With MySQL&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://dev.mysql.com/doc/refman/5.1/en/index-hints.html" target="_blank"&gt;Index Hint Syntax&lt;/a&gt; 

    &lt;p&gt;&lt;/p&gt;

    &lt;ul&gt;&lt;/ul&gt;

    &lt;p&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Explain and other techniques.&lt;/h4&gt;

&lt;p&gt;One of the most powerful tool for optimizing is EXPLAIN statement. It helps to analyze particular queries by showing the their execution plan. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Query 1&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s have a look at the EXPLAIN output for this query.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;id&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;select_type&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;table&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;type&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;possible_keys&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;key&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;key_len&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;ref&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;rows&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;Extra&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;SIMPLE&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;pictures&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;ALL&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;i&gt;NULL&lt;/i&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;i&gt;NULL&lt;/i&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;i&gt;NULL&lt;/i&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;i&gt;NULL&lt;/i&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;1000000&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;Using temporary; Using filesort&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;SIMPLE&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;types&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;ALL&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;PRIMARY&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;i&gt;NULL&lt;/i&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;i&gt;NULL&lt;/i&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;i&gt;NULL&lt;/i&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;4&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;Using where; Using join buffer&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;From the query execution plan we can see that unnecessary file sort is used. This is caused by GROUP BY clause. If you use GROUP BY, output rows are sorted according to the GROUP BY columns as if you had an ORDER BY for the same columns. To avoid the overhead of sorting that GROUP BY produces, add ORDER BY NULL.&lt;/p&gt;

&lt;p&gt;Most of the execution time is taken to process the &lt;em&gt;pictures&lt;/em&gt; table, while the one that is more interesting for this query is the &lt;em&gt;types&lt;/em&gt; table. &lt;/p&gt;

&lt;p&gt;To overcome this we can provide an extra column to the types tables – &lt;em&gt;types._count&lt;/em&gt;. Every time a picture is added, deleted or updated this column will be updated as well for a proper picture type. This way it will store the current number of pictures for every type. &lt;/p&gt;

&lt;p&gt;To keep the data coherent we can use procedures and triggers that works inside the database and are not depended on any external interface.&lt;/p&gt;

&lt;p&gt;We need two procedures – one to increase the counter of 1 another to decrease it of&amp;#160; 1.&lt;/p&gt;

&lt;pre class="brush: sql"&gt;DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `inc_pictures_type_counter`(IN type_id INT)
BEGIN
UPDATE types SET _count=_count+1 WHERE id=type_id;
END&lt;/pre&gt;

&lt;pre class="brush: sql"&gt;DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `dec_pictures_type_counter`(IN type_id INT)
BEGIN
UPDATE types SET _count=_count-1 WHERE id=type_id;
END&lt;/pre&gt;

&lt;p&gt;Now triggers. When we add a new picture of certain type the database has to call the procedure increasing the counter for that type - &lt;em&gt;inc_pictures_type_counter&lt;/em&gt;. &lt;/p&gt;

&lt;pre class="brush: sql"&gt;DROP TRIGGER IF EXISTS lost.on_insert_picture_type
CREATE TRIGGER lost.on_insert_picture_type AFTER INSERT ON lost.pictures
 FOR EACH ROW BEGIN
  CALL inc_pictures_type_counter(NEW.type_id);
END&lt;/pre&gt;

&lt;p&gt;When we delete a picture the database has to call the procedure decreasing the counter - &lt;em&gt;dec_pictures_type_counter&lt;/em&gt;. &lt;/p&gt;

&lt;pre class="brush: sql"&gt;DROP TRIGGER IF EXISTS lost.on_delete_picture_type
CREATE TRIGGER lost.on_delete_picture_type AFTER DELETE ON lost.pictures
 FOR EACH ROW BEGIN
  CALL dec_pictures_type_counter(OLD.type_id);
END&lt;/pre&gt;

&lt;p&gt;When the type of a picture is updated the database has to call the &lt;em&gt;dec_pictures_type_counter&lt;/em&gt; for the old type and then &lt;em&gt;inc_pictures_type_counter&lt;/em&gt; for the new type.&lt;/p&gt;

&lt;pre class="brush: sql"&gt;DROP TRIGGER IF EXISTS lost.on_update_picture_type
CREATE TRIGGER lost.on_update_picture_type AFTER UPDATE ON lost.pictures
 FOR EACH ROW BEGIN
  CALL dec_pictures_type_counter(OLD.type_id);  
  CALL inc_pictures_type_counter(NEW.type_id);
END&lt;/pre&gt;

&lt;p&gt;The new version of &lt;strong&gt;Query 1&lt;/strong&gt; uses only one table:&lt;/p&gt;

&lt;pre class="brush: sql"&gt;select name, _count from types;&lt;/pre&gt;

&lt;p&gt;and take less than 0,0001 s. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Query 2&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The execution plan for this query:&lt;/p&gt;

&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;id&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;select_type&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;table&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;type&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;possible_keys&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;key&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;key_len&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;ref&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;rows&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;Extra&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;SIMPLE&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;people&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;ALL&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;PRIMARY&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;i&gt;NULL&lt;/i&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;i&gt;NULL&lt;/i&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;i&gt;NULL&lt;/i&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;12&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;Using temporary; Using filesort&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;SIMPLE&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;people_pictures&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;ref&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;people_id&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;people_id&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;lost.people.id&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;250000&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;&amp;#160;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;Here we can see that the database first reads all &lt;em&gt;people.id&lt;/em&gt; and then the table &lt;em&gt;people_pictures&lt;/em&gt; is searched for rows where &lt;em&gt;people_pictures.people_id &lt;/em&gt;is equal to current &lt;em&gt;people.id&lt;/em&gt;. It means that the huge &lt;em&gt;people_pictures&lt;/em&gt;&amp;#160; table is searches 12 times and every time approximately 250000 rows are processes.&lt;/p&gt;

&lt;p&gt;Of course we sense that it would be faster to process the huge table once and join it with &lt;em&gt;people&lt;/em&gt; table when necessary. Let’s try to create new version of &lt;strong&gt;Query 2&lt;/strong&gt; that works this way:&lt;/p&gt;

&lt;pre class="brush: sql"&gt;select name, count(people_id) from people_pictures left join people on (people_pictures.people_id=people.id) group by people_id; &lt;/pre&gt;

&lt;p&gt;This query takes &lt;strong&gt;1,5s&lt;/strong&gt; and the query execution plan is now as follow:&lt;/p&gt;

&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;id&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;select_type&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;table&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;type&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;possible_keys&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;key&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;key_len&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;ref&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;rows&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;Extra&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;SIMPLE&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;people_pictures&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;index&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;i&gt;NULL&lt;/i&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;people_id&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;i&gt;NULL&lt;/i&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;3000000&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;Using index&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;SIMPLE&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;people&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;eq_ref&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;PRIMARY&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;PRIMARY&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;lost.people_pictures.people_id&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;&amp;#160;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;The &lt;em&gt;people_pictures&lt;/em&gt; table is processed one time.&amp;#160; Anyway the execution time is a bit too long. For this query we can use SQL_CACHE. The result set of this query will be cached and recomputed only in case, when any of involved tables changed. (If the caching mode is set &lt;code&gt;to query_cache_type = 2&lt;/code&gt; then you can use the &lt;code&gt;SQL_CACHE &lt;/code&gt;hint to tell MySQL which queries to cache.) With the SQL_CACHE hint the execution time is minimized to less than 0,0001 s.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Query 3&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Query 3 is the most complex and takes much more time then the others. Let’s see its execution plan:&lt;/p&gt;

&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;id&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;select_type&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;table&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;type&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;possible_keys&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;key&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;key_len&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;ref&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;rows&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;Extra&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;SIMPLE&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;people&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;ALL&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;PRIMARY&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;i&gt;NULL&lt;/i&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;i&gt;NULL&lt;/i&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;i&gt;NULL&lt;/i&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;12&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;Using temporary; Using filesort&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;SIMPLE&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;people_pictures&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;ref&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;picture_id,people_id&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;people_id&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;lost.people.id&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;250000&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;&amp;#160;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;SIMPLE&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;pictures&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;eq_ref&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;PRIMARY&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;PRIMARY&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;lost.people_pictures.picture_id&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;&amp;#160;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;The first used table is &lt;em&gt;people&lt;/em&gt;. The optimizer reads &lt;em&gt;people_pictures&lt;/em&gt; table for every &lt;em&gt;people.id –&lt;/em&gt; 12 times. Only then the &lt;em&gt;people_pictures&lt;/em&gt; is joined with &lt;em&gt;pictures&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Since we want to limit the result set to pictures that fulfill certain condition it seems more reasonable to use the table &lt;em&gt;pictures&lt;/em&gt; as first. Then we can join only these rows that left with the other two tables. The new version of &lt;strong&gt;Query 3&lt;/strong&gt; may be like this:&lt;/p&gt;

&lt;pre class="brush: sql"&gt;select filename, group_concat(people_id) from pictures left join people_pictures on (people_pictures.picture_id=pictures.id) left join people on (people_pictures.people_id=people.id) group by filename order by date limit 1,20;&lt;/pre&gt;
The time of this query is 42,5 s. 

&lt;p&gt;Not bad, but also not good enough. The execution plan:&lt;/p&gt;

&lt;table border="1" cellpadding="0"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;id&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;select_type&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;table&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;type&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;possible_keys&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;key&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;key_len&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;ref&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;rows&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;b&gt;Extra&lt;/b&gt;&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;SIMPLE&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;pictures&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;index&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;i&gt;NULL&lt;/i&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;date&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;8&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;&lt;i&gt;NULL&lt;/i&gt;&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;7&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;Using temporary&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;SIMPLE&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;people_pictures&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;ref&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;picture_id&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;picture_id&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;lost.pictures.id&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;3&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;&amp;#160;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;SIMPLE&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;people&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;eq_ref&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;PRIMARY&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;PRIMARY&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;lost.people_pictures.people_id&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;1&lt;/p&gt;
      &lt;/td&gt;

      &lt;td valign="top"&gt;
        &lt;p&gt;Using index&lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;If we think more about it, we may notice, that it&amp;#160; maybe better to choose only newest 20 pictures from &lt;em&gt;people_pictures&lt;/em&gt; and join the &lt;em&gt;people &lt;/em&gt;table with it. This way we could replace one conjunction with subquery. It would be something like this:&lt;/p&gt;

&lt;p&gt;&lt;pre class="brush: sql"&gt;select picture_id, group_concat(name) from people_pictures join people on (people_pictures.people_id=people.id) where picture_id in (select id from pictures order by date desc limit 1, 20) group by picture_id;&lt;/pre&gt;&lt;/p&gt;

&lt;p&gt;“Would be” -&amp;#160; because MySQL doesn’t allow LIMIT statement in subqueries.&lt;/p&gt;

&lt;p&gt;The thing we can do is to split these to two queries and join them in e.g. PHP like this:&lt;/p&gt;

&lt;pre class="brush: sql"&gt;$db=new PDO('mysql:host=localhost;dbname=lost-basic', 'root', '', array(PDO::ATTR_PERSISTENT =&amp;gt; false, PDO::ATTR_ERRMODE =&amp;gt; PDO::ERRMODE_EXCEPTION));

$query = 'select id from pictures order by date desc limit 1, 20;';
$res=$db-&amp;gt;query($query);

$pictures_array=array();

foreach($res as $row){
	foreach($row as $value){
		$pictures_array[]=$value;
	}	
}

$pictures = implode(', ', $pictures_array);

$query = &amp;quot;select picture_id, group_concat(name) from people_pictures join people on (people_pictures.people_id=people.id) where picture_id in ($pictures) group by picture_id&amp;quot;;
$res=$db-&amp;gt;query($query);
$res-&amp;gt;setFetchMode(PDO::FETCH_NUM);
$res-&amp;gt;fetchAll();

$db=null;&lt;/pre&gt;

&lt;p&gt;This works really fine and takes only 0,003 s.&lt;/p&gt;

&lt;h4&gt;Summary&lt;/h4&gt;

&lt;p&gt;As we can see there are many factors that influence the performance of the database but also many solutions for improving the execution time. We manage to decrease time for all queries to less than 0,01 s. &lt;/p&gt;

&lt;p&gt;These above ideas are just few from many others. It is very important is to observe the slow queries log. Such queries maybe then analyzed using EXPLAIN statement and then best solution for particular query can be used. &lt;/p&gt;

&lt;p&gt;Some other useful information here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://dev.mysql.com/doc/refman/5.5/en/optimization.html"&gt;http://dev.mysql.com/doc/refman/5.5/en/optimization.html&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://dev.mysql.com/doc/refman/5.0/en/handler.html"&gt;http://dev.mysql.com/doc/refman/5.0/en/handler.html&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://www.petefreitag.com/item/613.cfm"&gt;http://www.petefreitag.com/item/613.cfm&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://forge.mysql.com/wiki/MySQL_Internals_Algorithms"&gt;http://forge.mysql.com/wiki/MySQL_Internals_Algorithms&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;div id="related"&gt;
  &lt;p&gt;Related pots:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;&lt;a title="more advanced JOINs." href="http://thasha-in-wonderland.blogspot.com/2010/09/mysql-part-2-bit-more-advanced-joins.html" target="_blank"&gt;MySQL part 2: a bit more advanced JOINs.&lt;/a&gt; &lt;/li&gt;

    &lt;li&gt;&lt;a title="JOINs in a nutshell" href="http://thasha-in-wonderland.blogspot.com/2010/09/mysql-part-1-joins-in-nutshell.html"&gt;MySQL part 1: JOINs in a nutshell.&lt;/a&gt; &lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-6610243971665559502?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/6610243971665559502/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2010/09/mysql-part-3-optimization-hints.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/6610243971665559502'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/6610243971665559502'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2010/09/mysql-part-3-optimization-hints.html' title='MySQL part 3: optimization hints.'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_C4LysrTfKdY/TJc6N9deEhI/AAAAAAAAAdE/pcoEtuxV9JU/s72-c/lost-basic_thumb%5B2%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-5943888565360055103</id><published>2010-09-15T22:04:00.000+01:00</published><updated>2010-11-24T20:31:02.868Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL'/><title type='text'>MySQL part 2: a bit more advanced JOINs.</title><content type='html'>&lt;p&gt;&lt;a href="http://thasha-in-wonderland.blogspot.com/2010/09/mysql-part-1-joins-in-nutshell.html" target="_blank"&gt;Last time&lt;/a&gt; I explained the very basics of&amp;#160; JOINs. Now I will go a bit more further and show how to build more advanced queries. (I will continue on the same database.)&lt;/p&gt;  &lt;p&gt;First let’s remind the clauses order in the SELECT query:&lt;/p&gt;  &lt;p&gt;SELECT&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;FROM table_references&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;WHERE where_condition]&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;[GROUP BY {col_name | expr | position}&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;[ASC | DESC], ... [WITH ROLLUP]]&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;[HAVING where_condition]&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;[ORDER BY {col_name | expr | position}&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;[ASC | DESC], ...]&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;[LIMIT {[offset,] row_count | row_count OFFSET offset}]&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;WHERE indicates the condition or conditions that rows must satisfy to be selected. GROUP BY must be used with any aggregating functions to group the resultset by one or more columns. HAVING works only with GROUP BY and should be used only with aggregation functions (while the WHERE clause cannot). ORDER BY is used to order the result set by a desired column or columns.&lt;/p&gt;  &lt;h4&gt;Many-To-Many&lt;/h4&gt;  &lt;p&gt;Let’s choose all pictures with a list of people tagged on each of them. This is a many-to-many relation that requires two joins. &lt;/p&gt;  &lt;pre class="brush: sql"&gt;select filename, name from people_pictures join pictures on (people_pictures.picture_id = pictures.id) join people on (people_pictures.people_id=people.id);&lt;/pre&gt;

&lt;br /&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;picture1.jpg&lt;/td&gt;

      &lt;td&gt;Jack&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture1.jpg&lt;/td&gt;

      &lt;td&gt;Ben&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture1.jpg&lt;/td&gt;

      &lt;td&gt;Claire&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture2.jpg&lt;/td&gt;

      &lt;td&gt;John&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture2.jpg&lt;/td&gt;

      &lt;td&gt;Jack&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture2.jpg&lt;/td&gt;

      &lt;td&gt;Ben&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture3.jpg&lt;/td&gt;

      &lt;td&gt;Jin&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture3.jpg&lt;/td&gt;

      &lt;td&gt;Jack&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture5.jpg&lt;/td&gt;

      &lt;td&gt;John&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture5.jpg&lt;/td&gt;

      &lt;td&gt;Sun&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;The result set has many rows with the same filenames. Sometimes this can be a disadvantage. There is an easy way to show every picture with coma-separated list of tagged characters. For that we can use &lt;strong&gt;group_concat&lt;/strong&gt; function with GROUP BY clause:&lt;/p&gt;

&lt;pre class="brush: sql"&gt;select filename, group_concat(name) from people_pictures join pictures on (people_pictures.picture_id = pictures.id) join people on (people_pictures.people_id=people.id) group by filename;&lt;/pre&gt;

&lt;br /&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;picture1.jpg&lt;/td&gt;

      &lt;td&gt;Jack,Claire,Ben&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture2.jpg&lt;/td&gt;

      &lt;td&gt;Ben,Jack,John&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture3.jpg&lt;/td&gt;

      &lt;td&gt;Jack,Jin&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture5.jpg&lt;/td&gt;

      &lt;td&gt;Sun,John&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;If we need to exclude some results on some conditions we can use HAVING clause. Let’s choose only the pictures with at least three people tagged on them.&lt;/p&gt;

&lt;pre class="brush: sql"&gt;select filename from people_pictures join pictures on (people_pictures.picture_id = pictures.id) join people on (people_pictures.people_id=people.id) group by filename having count(name)&amp;gt;2;&lt;/pre&gt;

&lt;br /&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;picture1.jpg&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture2.jpg&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;br /&gt;

&lt;p&gt;We can also find all pictures with Jack.&lt;/p&gt;

&lt;pre class="brush: sql"&gt;select filename from people_pictures join people on (people_pictures.people_id = people.id) join pictures on (people_pictures.picture_id=pictures.id) where name = 'Jack';&lt;/pre&gt;

&lt;br /&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;picture1.jpg&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture2.jpg&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture3.jpg&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;At the end let’s find the most tagged character. &lt;/p&gt;

&lt;pre class="brush: sql"&gt;select people.name from people_pictures join people on (people_pictures.people_id = people.id) group by people_id order by count(people_id) desc limit 1;&lt;/pre&gt;

&lt;br /&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Jack&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;br /&gt;All above examples work just fine for small database. However the loading time grows with the number of records. Next time I will show how to optimize such queries to keep the loading time reasonable . 

&lt;div id="related"&gt;
  &lt;p&gt;Related pots:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;&lt;a title="JOINs in a nutshell" href="http://thasha-in-wonderland.blogspot.com/2010/09/mysql-part-1-joins-in-nutshell.html"&gt;MySQL part 1: JOINs in a nutshell.&lt;/a&gt; &lt;/li&gt;

    &lt;li&gt;&lt;a title="MySQL optimization" href="http://thasha-in-wonderland.blogspot.com/2010/09/mysql-part-3-optimization-hints.html"&gt;MySQL part 3: optimization hints.&lt;/a&gt; &lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-5943888565360055103?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/5943888565360055103/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2010/09/mysql-part-2-bit-more-advanced-joins.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/5943888565360055103'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/5943888565360055103'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2010/09/mysql-part-2-bit-more-advanced-joins.html' title='MySQL part 2: a bit more advanced JOINs.'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-5965860663148914719</id><published>2010-09-14T21:58:00.000+01:00</published><updated>2010-12-11T15:24:25.053Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL'/><title type='text'>MySQL part 1: JOINs in a nutshell.</title><content type='html'>&lt;p&gt;Recently I decided to go more deep in the topic of&amp;#160; MySQL optimization. However, to start working on this issue I needed to organize my expertise in this field. This way this short “memo” is created. Maybe it will be useful for somebody…&lt;/p&gt;  &lt;p&gt;So, here we go.&lt;/p&gt;  &lt;p&gt;First of all, we need some sample database. I love &lt;em&gt;The Lost&lt;/em&gt; series, so I thought up a database for storing pictures of the main characters.&lt;/p&gt;  &lt;p&gt;The information we want to save in this database are as follows:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Every picture has a file name and a date when it was taken. &lt;/li&gt;    &lt;li&gt;Every picture may be associated a type and a place where it was taken. &lt;/li&gt;    &lt;li&gt;Additionally every character can be tagged on several pictures, and every picture can be tagged with several characters (many-to-many) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_C4LysrTfKdY/TJEzqZ3Se8I/AAAAAAAAAc4/4oz6-9aZJ-M/s1600-h/lost-basic%5B5%5D.png"&gt;&lt;img style="display: inline" title="lost-basic" alt="lost-basic" src="http://lh6.ggpht.com/_C4LysrTfKdY/TJEzq3RddoI/AAAAAAAAAc8/Bg27zL81WIs/lost-basic_thumb%5B3%5D.png?imgmax=800" width="466" height="271" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://thashawonderland.appspot.com/files/mysql/lost-basic-data.sql" target="_blank"&gt;Here you can find the SQL script for this DB.&lt;/a&gt;&lt;/p&gt; To warm up let’s start with something simple…   &lt;p&gt;We have to choose pictures and the types related to them (only if the picture has a type). We can do it in two ways:&lt;/p&gt; using WHERE:   &lt;pre class="brush: sql"&gt;select filename, name from pictures, types where pictures.type_id=types.id;&lt;/pre&gt;
or using JOIN: 

&lt;pre class="brush: sql"&gt;select filename, name from pictures join types on (pictures.type_id = types.id);&lt;/pre&gt;
In both cases the result set will be: 

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;picture1.jpg&lt;/td&gt;

      &lt;td&gt;funny&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture5.jpg&lt;/td&gt;

      &lt;td&gt;funny&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture4.jpg&lt;/td&gt;

      &lt;td&gt;landscape&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture2.jpg&lt;/td&gt;

      &lt;td&gt;misc&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;In this case WHERE and JOIN work well, however they work like intersection.&lt;/p&gt;

&lt;h4&gt;LEFT JOIN&lt;/h4&gt;

&lt;p&gt;Imagine situation when you need all pictures. Doesn’t matter if they have a type. In such case you can use LEFT JOIN (what means, that the query returns all rows from the left table, even if there are no matches in the right table).&lt;/p&gt;

&lt;pre class="brush: sql"&gt;select filename, name from pictures left join types on (pictures.type_id = types.id);&lt;/pre&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;picture1.jpg&lt;/td&gt;

      &lt;td&gt;funny&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture2.jpg&lt;/td&gt;

      &lt;td&gt;misc&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture3.jpg&lt;/td&gt;

      &lt;td&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture4.jpg&lt;/td&gt;

      &lt;td&gt;landscape&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture5.jpg&lt;/td&gt;

      &lt;td&gt;funny&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;br /&gt;

&lt;h4&gt;RIGHT JOIN&lt;/h4&gt;

&lt;p&gt;We can also do something opposite: chose all types and join the pictures that belongs to them:&lt;/p&gt;

&lt;pre class="brush: sql"&gt;select filename, name from pictures right join types on (pictures.type_id = types.id);&lt;/pre&gt;

&lt;p&gt;This time we used RIGHT JOIN (the query returns all rows from the right table, even if there are no matches in the left table). &lt;/p&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;picture1.jpg&lt;/td&gt;

      &lt;td&gt;funny&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture5.jpg&lt;/td&gt;

      &lt;td&gt;funny&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture4.jpg&lt;/td&gt;

      &lt;td&gt;landscape&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture2.jpg&lt;/td&gt;

      &lt;td&gt;misc&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;&lt;/td&gt;

      &lt;td&gt;portrait&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;In most cases we can use LEFT or RIGHT JOIN to get the same results (anyway it is recommended using LEFT JOIN).&lt;/p&gt;

&lt;pre class="brush: sql"&gt;select filename, name from types left join pictures on (pictures.type_id = types.id);&lt;/pre&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;picture1.jpg&lt;/td&gt;

      &lt;td&gt;funny&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture5.jpg&lt;/td&gt;

      &lt;td&gt;funny&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture4.jpg&lt;/td&gt;

      &lt;td&gt;landscape&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture2.jpg&lt;/td&gt;

      &lt;td&gt;misc&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;&lt;/td&gt;

      &lt;td&gt;portrait&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;h4&gt;NATURAL JOIN&lt;/h4&gt;

&lt;p&gt;Another type of join is NATURAL JOIN. We can use it in case when we want to join two (or more) tables using columns with the same names. NATURAL JOIN works without any join condition. (You must be careful: if you have a habit to name primary key column “id”, MySQL may use this column to create the conjunction.)&lt;/p&gt;

&lt;pre class="brush: sql"&gt;select filename, name from pictures natural join places;&lt;/pre&gt;

&lt;table border="1"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;picture1.jpg&lt;/td&gt;

      &lt;td&gt;Los Angeles&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture2.jpg&lt;/td&gt;

      &lt;td&gt;Sydney&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture4.jpg&lt;/td&gt;

      &lt;td&gt;Sydney&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;picture3.jpg&lt;/td&gt;

      &lt;td&gt;The Island&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;&lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;In this case both tables have a column named “place_id” and this column is used to create relationship. &lt;/p&gt;

&lt;p&gt;At the end it is worth mentioning INNER and CROSS JOIN. In MySQL they are equivalent to each other and produce exactly the same result as JOIN. &lt;/p&gt;

&lt;p&gt;You can find more about JOINs here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://dev.mysql.com/doc/refman/5.1/en/join.html" target="_blank"&gt;http://dev.mysql.com/doc/refman/5.1/en/join.html&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://www.w3schools.com/sql/sql_join.asp" target="_blank"&gt;http://www.w3schools.com/sql/sql_join.asp&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://mysql-join.com/reference/mysql-supported-joins/"&gt;http://mysql-join.com/reference/mysql-supported-joins/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div id="related"&gt;
  &lt;p&gt;Related pots:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;&lt;a title="more advanced JOINs." href="http://thasha-in-wonderland.blogspot.com/2010/09/mysql-part-2-bit-more-advanced-joins.html" target="_blank"&gt;MySQL part 2: a bit more advanced JOINs.&lt;/a&gt; &lt;/li&gt;

    &lt;li&gt;&lt;a title="MySQL optimization" href="http://thasha-in-wonderland.blogspot.com/2010/09/mysql-part-3-optimization-hints.html"&gt;MySQL part 3: optimization hints.&lt;/a&gt; &lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-5965860663148914719?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/5965860663148914719/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2010/09/mysql-part-1-joins-in-nutshell.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/5965860663148914719'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/5965860663148914719'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2010/09/mysql-part-1-joins-in-nutshell.html' title='MySQL part 1: JOINs in a nutshell.'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_C4LysrTfKdY/TJEzq3RddoI/AAAAAAAAAc8/Bg27zL81WIs/s72-c/lost-basic_thumb%5B3%5D.png?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-4403991646700600956</id><published>2009-12-14T16:48:00.001Z</published><updated>2010-11-24T20:05:21.463Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='google wave'/><category scheme='http://www.blogger.com/atom/ns#' term='embed waves'/><category scheme='http://www.blogger.com/atom/ns#' term='AuthSub'/><category scheme='http://www.blogger.com/atom/ns#' term='blogger api'/><title type='text'>Wave blogging… and how it leads me to create my first robot.</title><content type='html'>&lt;p&gt;Some time ago I have created a “wave” with some funny stuff to share it among my friends. It is working OK, every one of us can put something funny or comment it. But for me there is one missing feature. I cannot directly embed that wave on my blog. (Since I have two blogs, I would prefer also to have choice where exactly I wish to publish this wave.) I would not mind also to give me friends, or everyone, a possibility to comment it.&lt;/p&gt;  &lt;p&gt;Since both, Blogger (that I use) and Wave, are from Google, it seemed that they should work already together, but the reality is different.&lt;/p&gt;  &lt;p&gt;In the Google Wave Developer Preview video we could see a robot that publish a wave on a special blog . It was bloggy (currently blog-wave@appspot.com ). It evaluates now a bit and the last working version publish the blog on http://blog-wave.appspot.com/your_wave_nickname. Currently is not working.&lt;/p&gt;  &lt;p&gt;In the meantime a special kind of user - public@a.googlewave.com&amp;#160; - has been created. It changed recently to easypublic@appspot.com and gives access to everyone who find the wave&lt;strong&gt; .&lt;/strong&gt; (To find public waves search for &lt;strong&gt;group:public&lt;/strong&gt;.)&lt;/p&gt;  &lt;p&gt;There is also a possibility to embed a wave in desired website using JavaScript. Very good tutorial about it is here:&lt;strong&gt; &lt;/strong&gt;&lt;a href="http://code.google.com/intl/pl/apis/wave/embed/guide.html"&gt;http://code.google.com/intl/pl/apis/wave/embed/guide.html&lt;/a&gt;. The one thing here is that we need to know an&lt;strong&gt; id of the wave&lt;/strong&gt; we want to embed. For that exist already some solutions e.g. robot embeddy (&lt;a href="mailto:embeddy@appspot.com"&gt;embeddy@appspot.com&lt;/a&gt;) that generates the whole JavaScript with the wave id included. &lt;/p&gt;  &lt;p&gt;With a small template modification it is also possible to &lt;strong&gt;embed a wave inBlogger&lt;/strong&gt;. We only need to keep in mind that the div id must be unique. The modification can be e.g. as follow:&lt;/p&gt;  &lt;p&gt;In head section of the template:&lt;/p&gt;  &lt;pre class="brush: js"&gt;&amp;lt;script&amp;gt;
function showWave(elementId, waveId){
  document.write(&amp;quot;&amp;lt;div id=&amp;quot;+elementId+&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;);
  var wave =new WavePanel('https://wave.google.com/wave/');
  wave.setUIConfig('white', 'black', 'Arial', '13px');
  wave.loadWave(waveId);
  wave.init(document.getElementById(elementId));
}
&amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;p&gt;Since the template is already modified, it is enough just one line of code to embed a wave:&lt;/p&gt;

&lt;pre class="brush: js"&gt;&amp;lt;script&amp;gt;
showWave('unique div id ','googlewave_id…');
&amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;p&gt;This is working really fine but it is not the same as publishing from a blip.&lt;/p&gt;

&lt;p&gt;Google Wave is almost ideal to create extensions for it. I decided to try to create a robot that will help to publish a wave on a Blogger blog. This robot lives under &lt;a href="mailto:blogroby@appspot.com"&gt;&lt;strong&gt;blogroby@appspot.com&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The source code of this robot is here: &lt;a href="https://code.google.com/p/blogroby/source/browse/#svn/trunk" target="_blank"&gt;https://code.google.com/p/blogroby/source/browse/#svn/trunk&lt;/a&gt; If someone feels like to extend it, is very welcome. &lt;/p&gt;

&lt;p&gt;This robot involves Google Appengine, Blogger API and AuthSub authorization. Describing everything step by step would be a bit complicated. I will just highlight some issues and give links to all the documentation.&lt;/p&gt;

&lt;p&gt;My robot consists of two parts. Blogroby.py which is the real robot and Publish.py which is responsible for creating a draft posts with embedded wave. &lt;/p&gt;

&lt;p&gt;The only thing what blogroby actually does is to create a link that will authorize publish.py (that lies under &lt;a href="http://blogroby.appspot.com/"&gt;http://blogroby.appspot.com/&lt;/a&gt;) to the Blogger service. For authorization AuthSub proxy is used, so you newer pass your password to my application. (More about the authorization here: &lt;a href="http://code.google.com/intl/pl/apis/blogger/docs/1.0/developers_guide_python.html#Authenticating"&gt;http://code.google.com/intl/pl/apis/blogger/docs/1.0/developers_guide_python.html#Authenticating&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;This link passes also a wave id to the publish.py.&lt;/p&gt;

&lt;p&gt;Publish.py is a simple Python webapp framework application. (&lt;a href="http://code.google.com/intl/pl/appengine/docs/python/gettingstarted/usingwebapp.html"&gt;http://code.google.com/intl/pl/appengine/docs/python/gettingstarted/usingwebapp.html&lt;/a&gt;) This script first prints a list of your blogs and ask on which blog you want to embed a wave. You choose one blog by clicking its name and then a draft post is created. To avoid double authorization I keep &lt;strong&gt;Auth Session Token&lt;/strong&gt; in session, and since webapp doesn’t support session I used GAEUtilities for that (&lt;a href="http://code.google.com/p/gaeutilities/"&gt;http://code.google.com/p/gaeutilities/&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;That’s it . Enjoy.&lt;/p&gt;
PS. I noticed problems with getting blog list when even one blog’s name have any national character. 

&lt;p&gt;The wave below demonstrates blogroby. (Visible only for those who are currently logged into Google Wave.)&lt;/p&gt;
&lt;script&gt;
showWave('pierwsza','googlewave.com!w+pjT6DjsEA');
&lt;/script&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-4403991646700600956?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/4403991646700600956/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/12/wave-blogging-and-how-it-leads-me-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/4403991646700600956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/4403991646700600956'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/12/wave-blogging-and-how-it-leads-me-to.html' title='Wave blogging… and how it leads me to create my first robot.'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-2743594026715179994</id><published>2009-10-17T22:25:00.001+01:00</published><updated>2010-11-24T19:56:25.828Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='google map'/><title type='text'>Google Maps car on my street.</title><content type='html'>&lt;p&gt;And this how it really looks like….&lt;/p&gt;  &lt;div align="center"&gt;   &lt;table border="0" cellspacing="0" cellpadding="2" width="400" align="center"&gt;&lt;tbody&gt;       &lt;tr&gt;         &lt;td valign="top" width="200"&gt;&lt;a href="http://lh5.ggpht.com/_C4LysrTfKdY/Sto2TOmqOtI/AAAAAAAAASs/IkXN5j7fgvI/s1600-h/IMG_5418%5B2%5D.jpg"&gt;&lt;img style="display: inline" title="IMG_5418" alt="IMG_5418" src="http://lh3.ggpht.com/_C4LysrTfKdY/Sto2T5ux2LI/AAAAAAAAASw/fk87Yju3d9k/IMG_5418_thumb.jpg?imgmax=800" width="240" height="180" /&gt;&lt;/a&gt;&lt;/td&gt;          &lt;td valign="top" width="200"&gt;&lt;a href="http://lh6.ggpht.com/_C4LysrTfKdY/Sto2U1vc50I/AAAAAAAAAS0/Eo3HWNvDVkI/s1600-h/IMG_5419%5B2%5D.jpg"&gt;&lt;img style="display: inline" title="IMG_5419" alt="IMG_5419" src="http://lh5.ggpht.com/_C4LysrTfKdY/Sto2Vgcg5YI/AAAAAAAAAS4/hHGL8BfU7ZU/IMG_5419_thumb.jpg?imgmax=800" width="180" height="240" /&gt;&lt;/a&gt; &lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-2743594026715179994?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/2743594026715179994/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/10/google-maps-car-on-my-street.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/2743594026715179994'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/2743594026715179994'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/10/google-maps-car-on-my-street.html' title='Google Maps car on my street.'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_C4LysrTfKdY/Sto2T5ux2LI/AAAAAAAAASw/fk87Yju3d9k/s72-c/IMG_5418_thumb.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-851237839985513382</id><published>2009-10-14T18:26:00.001+01:00</published><updated>2010-11-24T19:52:10.524Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='CakePHP 1.2'/><title type='text'>CakePHP 1.2 - dynamical validation rules.</title><content type='html'>&lt;p&gt;Many times we need to use one model in many forms with different validation rules. This is not only the case when we have a form to add some information and a form to edit this information (then we can use &lt;em&gt;on create&lt;/em&gt; and &lt;em&gt;on update&lt;/em&gt;). For example: we have one User model and two different forms to add a user. During the registration a user can subscribe for a basic account or for an extended account. For the basic account is enough that the user will input just the username and password. For extended account the user is obligated to give also his personal data. To distinguish between these requests there is a checkbox (&lt;em&gt;isextended&lt;/em&gt;) that the user can select if he wants to subscribe for extended account.&lt;/p&gt;  &lt;p&gt;The problem appears while validating this form. How to indicate that the personal data is required in case the user is subscribing for extended account…? If we mark these fields as required in the model (&lt;em&gt;var $validate&lt;/em&gt;) the validation rules will apply also if the user subscribe only for basic account. Consequently if the user subscribe for the basic account the form will not validate.&lt;/p&gt;  &lt;p&gt;Well, the solution for the problem is very simply.&lt;/p&gt;  &lt;p&gt;In the User model the &lt;em&gt;var $validate&lt;/em&gt; table must have only rules for these fields that must validate always. &lt;/p&gt;  &lt;pre class="brush: php"&gt;var $validate = array(
  'username' =&amp;gt; array(
    'between' =&amp;gt; array(
      'rule'      =&amp;gt; array('between', 6, 20),
      'required'  =&amp;gt; true,
     ),
  ),
  'password' =&amp;gt; array(
    'empty' =&amp;gt; array(
      'rule'      =&amp;gt; 'notEmpty',
      'required'  =&amp;gt; true,
    ),
  ),
);&lt;/pre&gt;

&lt;p&gt;Then we create another table with the same structure for example: $validate_extended with rules that must validate on some conditions – extended account. &lt;/p&gt;

&lt;pre class="brush: php"&gt;var $validate_extended =array(
  'name' =&amp;gt; array(
    'maxLength' =&amp;gt; array(
      'rule'      =&amp;gt; array('maxLength', 128),
      'required'=&amp;gt;true,
    ),
  ),
  'address' =&amp;gt; array(
     'empty' =&amp;gt; array(
      'rule'      =&amp;gt; 'notEmpty',
      'required'  =&amp;gt; true,
    ),
  ),
);&lt;/pre&gt;

&lt;p&gt;The validation is carried out just before save(). Therefore we can read from the&lt;em&gt; $this-&amp;gt;data[‘User’][‘isextended’]&lt;/em&gt; and if the request is for extended account we merge these two validation tables in one&lt;em&gt; $validate.&lt;/em&gt;&lt;/p&gt;

&lt;pre class="brush: php"&gt;class UsersController extends AppController {
(...)
function add() {
  if (!empty($this-&amp;gt;data)) {

  if($this-&amp;gt;data['User']['isextended']==1){
   $this-&amp;gt;User-&amp;gt;validate=array_merge($this-&amp;gt;User-&amp;gt;validate, $this-&amp;gt;User-&amp;gt;validate_extended);	
  }
	(...)		
  if ($this-&amp;gt;User-&amp;gt;save($this-&amp;gt;data)) {...}
}
}
}&lt;/pre&gt;

&lt;p&gt;Enjoy.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-851237839985513382?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/851237839985513382/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/10/cakephp-how-to-dynamically-load.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/851237839985513382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/851237839985513382'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/10/cakephp-how-to-dynamically-load.html' title='CakePHP 1.2 - dynamical validation rules.'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-7329414636791558840</id><published>2009-09-09T15:09:00.001+01:00</published><updated>2010-11-24T19:44:27.587Z</updated><title type='text'>Monopoly – first shots.</title><content type='html'>&lt;p&gt;Despite the first announcements the game is “working” already. Unfortunately “working” does not mean you can play it. The servers are overloaded and 99% of the time they don’t respond.&lt;/p&gt;  &lt;p&gt;With a huge dose of patience I manage to find a street to buy, and… I have got stuck in user registration form for last 30 minutes.&lt;/p&gt;  &lt;p&gt;First impressions: looks nice, pity it is not possible to play, the registration form has some small bugs (i.e. after reload remembers you password while didn’t remember you nick name.&lt;/p&gt;  &lt;p&gt;First pictures:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_C4LysrTfKdY/Sqe3B68EVOI/AAAAAAAAAPk/YQrGHULJTOw/s1600-h/1%5B3%5D.jpg"&gt;&lt;img style="display: inline" title="1" alt="1" src="http://lh6.ggpht.com/_C4LysrTfKdY/Sqe3Cv6EIuI/AAAAAAAAAPo/PD-C6oOHzr0/1_thumb%5B1%5D.jpg?imgmax=800" width="240" height="148" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_C4LysrTfKdY/Sqe3Dbq4s-I/AAAAAAAAAPs/ohV3NxWZdto/s1600-h/2%5B2%5D.jpg"&gt;&lt;img style="display: inline" title="2" alt="2" src="http://lh5.ggpht.com/_C4LysrTfKdY/Sqe3D3x6v2I/AAAAAAAAAPw/exLrnFsnkxg/2_thumb.jpg?imgmax=800" width="240" height="110" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_C4LysrTfKdY/Sqe3E0QEQqI/AAAAAAAAAP0/PmkheL8DCkY/s1600-h/3%5B2%5D.jpg"&gt;&lt;img style="display: inline" title="3" alt="3" src="http://lh4.ggpht.com/_C4LysrTfKdY/Sqe3FW93jpI/AAAAAAAAAP4/OAadsNEaGDc/3_thumb.jpg?imgmax=800" width="240" height="111" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_C4LysrTfKdY/Sqe3GQrNZZI/AAAAAAAAAP8/cH5HTkrp2wg/s1600-h/4%5B2%5D.jpg"&gt;&lt;img style="display: inline" title="4" alt="4" src="http://lh3.ggpht.com/_C4LysrTfKdY/Sqe3HEiTGfI/AAAAAAAAAQA/jn_SznS6W7o/4_thumb.jpg?imgmax=800" width="240" height="107" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Sadly, on the official blog there are many comments saying that there are much more bugs in the game.&amp;#160; Maybe Google or Hasbro rush into making it available for public...&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Edit: Perhaps a big reset is coming.&lt;/em&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-7329414636791558840?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/7329414636791558840/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/09/monopoly-first-shots.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/7329414636791558840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/7329414636791558840'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/09/monopoly-first-shots.html' title='Monopoly – first shots.'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_C4LysrTfKdY/Sqe3Cv6EIuI/AAAAAAAAAPo/PD-C6oOHzr0/s72-c/1_thumb%5B1%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-5984934412293874768</id><published>2009-09-08T17:40:00.001+01:00</published><updated>2010-11-24T19:42:23.719Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='google'/><category scheme='http://www.blogger.com/atom/ns#' term='google map'/><title type='text'>Tomorrow I will be lost (to the world)…</title><content type='html'>&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_C4LysrTfKdY/SqaI7HO1ZtI/AAAAAAAAAPc/pHmXZJmfWmE/s1600-h/File%5B5%5D.png"&gt;&lt;img style="display: inline; margin-left: 0px; margin-right: 0px" title="Monopoly !!!" alt="Monopoly !!!" align="left" src="http://lh5.ggpht.com/_C4LysrTfKdY/SqaI7w8foxI/AAAAAAAAAPg/YZk5XlLx1EA/File_thumb%5B3%5D.png?imgmax=800" width="220" height="110" /&gt;&lt;/a&gt;&amp;#160; …and my project with me. Everything because of Google: &lt;a href="http://blog.monopolycitystreets.com/" target="_blank"&gt;http://blog.monopolycitystreets.com/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;So, see you tomorrow on &lt;a href="http://www.monopolycitystreets.com/" target="_blank"&gt;http://www.monopolycitystreets.com/&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-5984934412293874768?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/5984934412293874768/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/09/tomorrow-i-will-be-lost-to-world.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/5984934412293874768'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/5984934412293874768'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/09/tomorrow-i-will-be-lost-to-world.html' title='Tomorrow I will be lost (to the world)…'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_C4LysrTfKdY/SqaI7w8foxI/AAAAAAAAAPg/YZk5XlLx1EA/s72-c/File_thumb%5B3%5D.png?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-579165922887530749</id><published>2009-08-31T20:47:00.001+01:00</published><updated>2010-11-24T19:54:40.324Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='CakePHP 1.2'/><title type='text'>CakePHP 1.2 – Introduction to Ajax</title><content type='html'>&lt;p&gt;After I have finished reading the Ajax Helper section in the Cookbook I felt unsatisfied - it lacks more complex examples. To understand it better I played a bit with it. Below example is a compilation of my conclusions.&lt;/p&gt;  &lt;p&gt;We have two simple models linked with one relation: every User belongs to a City.&lt;/p&gt;  &lt;p&gt;The goal is to display all Users in a select box. Every time a user is selected, user’s city appears below the control. &lt;/p&gt;  &lt;p&gt;DB tables for this example:&lt;/p&gt;  &lt;pre class="brush: sql"&gt;CREATE TABLE IF NOT EXISTS `cities` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

INSERT INTO `cities` (`id`, `name`) VALUES
(1, 'Warsaw'),
(2, 'Paris'),
(3, 'Lisbon');

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `city_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

INSERT INTO `users` (`id`, `name`, `city_id`) VALUES
(1, 'Anna', 1),
(2, 'Georges', 2),
(3, 'Rui', 3);&lt;/pre&gt;

&lt;p&gt;First of all, we have to generate every model, view and controller using the cake bake.&lt;/p&gt;

&lt;p&gt;Secondly,&amp;#160; we have to prepare the view: views/users/index.ctp&lt;/p&gt;

&lt;pre class="brush: php"&gt;&amp;lt;!-- 
Cake uses Prototype for Ajax operations, 
so first of all we need to link it to the 
desired view.
--&amp;gt;
&amp;lt;?php echo $javascript-&amp;gt;link('/js/prototype'); ?&amp;gt;

&amp;lt;!--
Create select box.
--&amp;gt;
&amp;lt;?php echo $form-&amp;gt;select('user',$users_list);?&amp;gt;

&amp;lt;!-- 
Create div for Ajax update. 
Inside this div there is a tiny gif indicating
that the update is loading.
--&amp;gt;
&amp;lt;div id='city'&amp;gt;
&amp;lt;img src=&amp;quot;/ajax/img/progress.gif&amp;quot; alt=&amp;quot;progress&amp;quot; id=&amp;quot;progress&amp;quot; style=&amp;quot;display:none&amp;quot;&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;!-- 
Ads observer to the select box, when the select 
box is updated call the function specified by 
'url' property.
While loading the Ajax update enable visibility 
of 'indicator'.
--&amp;gt;

&amp;lt;?php
echo $ajax-&amp;gt;observeField('user', array(
	//function called by Ajax
	'url' =&amp;gt;'getCity',
	//id of element to be updated
	'update' =&amp;gt; 'city',
	//enable visibility of indicator 
	'indicator'=&amp;gt;'progress',
	));
?&amp;gt;&lt;/pre&gt;

&lt;p&gt;Then we need to take care about the controller: controllers/user_controller.php. First, we have to add the needed helpers and components:&lt;/p&gt;

&lt;pre class="brush: php"&gt;var $helpers = array('Html', 'Form', 'Javascript','Ajax');
var $components = array('RequestHandler');&lt;/pre&gt;

&lt;p&gt;…and then we need to prepare data to populate our select box.&lt;/p&gt;

&lt;pre class="brush: php"&gt;function index() {
	(...)
	$users_list=$this-&amp;gt;User-&amp;gt;find('list');
	$this-&amp;gt;set('users_list', $users_list);
}&lt;/pre&gt;

&lt;p&gt;In the last step for the controller we create a function that handle the Ajax request:&lt;/p&gt;

&lt;pre class="brush: php"&gt;function getCity($id=null){
	if(!empty($this-&amp;gt;data['user'])){
		$user=$this-&amp;gt;User-&amp;gt;read(null, $this-&amp;gt;data['user']);
		$this-&amp;gt;set('city',$user['City']['name']);
	}
	else{
		$this-&amp;gt;set('city',&amp;quot; &amp;quot;);
	}
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Update:&lt;/u&gt;&lt;/strong&gt; Here I should mention that this view will be also accessible browser window. To avoid it we should check first if the request is really an Ajax request:&lt;/p&gt;

&lt;pre class="brush: php"&gt;function getCity($id=null){
  if($this-&amp;gt;RequestHandler-&amp;gt;isAjax()){
    if(!empty($this-&amp;gt;data['user'])){
	$user=$this-&amp;gt;User-&amp;gt;read(null, $this-&amp;gt;data['user']);
	$this-&amp;gt;set('city',$user['City']['name']);
    }
    else{
	$this-&amp;gt;set('city',&amp;quot; &amp;quot;);
    }
  else{
      $this-&amp;gt;Session-&amp;gt;setFlash(__('Invalid request', true));
  }
}&lt;/pre&gt;

&lt;p&gt;Finally, we need to create a view for getCity() - views/users/get_city.ctp. This view will be loaded inside the defined tag in the index view.&lt;/p&gt;

&lt;pre class="brush: php"&gt;&amp;lt;?php echo $city; ?&amp;gt;&lt;/pre&gt;

&lt;p&gt;As a result every time we select a user from the select box the city of the selected user should appear below preceded by a progress indicator.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_C4LysrTfKdY/Sp5PwuucX4I/AAAAAAAAAPM/VVx0Vcf8d0A/s1600-h/a%5B3%5D.jpg"&gt;&lt;img style="display: inline" title="a" alt="a" src="http://lh3.ggpht.com/_C4LysrTfKdY/Sp5PxJY0XeI/AAAAAAAAAPQ/8_h73HXY24Y/a_thumb%5B1%5D.jpg?imgmax=800" width="120" height="56" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_C4LysrTfKdY/Sp5Pxr0JiQI/AAAAAAAAAPU/bHtykc-qSl0/s1600-h/b%5B3%5D.jpg"&gt;&lt;img style="display: inline" title="b" alt="b" src="http://lh5.ggpht.com/_C4LysrTfKdY/Sp5PyVy5ZEI/AAAAAAAAAPY/zVRLRthEdCk/b_thumb%5B1%5D.jpg?imgmax=800" width="114" height="54" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;BTW: nice loading indicators generator: &lt;a href="http://www.webscriptlab.com/" target="_blank"&gt;http://www.webscriptlab.com/&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-579165922887530749?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/579165922887530749/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/08/cakephp-introduction-to-ajax.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/579165922887530749'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/579165922887530749'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/08/cakephp-introduction-to-ajax.html' title='CakePHP 1.2 – Introduction to Ajax'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_C4LysrTfKdY/Sp5PxJY0XeI/AAAAAAAAAPQ/8_h73HXY24Y/s72-c/a_thumb%5B1%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-2853717794415359611</id><published>2009-08-24T18:15:00.001+01:00</published><updated>2010-11-24T19:28:22.682Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='google wave'/><title type='text'>WOW !! I got Google Wave sandbox account.</title><content type='html'>&lt;p&gt;… and you cannot imagine how I’m happy with this fact.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_C4LysrTfKdY/SpLKldtDHaI/AAAAAAAAANg/Tm2_ruIpMiU/s1600-h/Bez%20nazwy%5B7%5D.jpg"&gt;&lt;img style="display: inline" title="Bez nazwy" alt="Bez nazwy" src="http://lh5.ggpht.com/_C4LysrTfKdY/SpLKnOz-TiI/AAAAAAAAANk/31nMNBK3l8E/Bez%20nazwy_thumb%5B5%5D.jpg?imgmax=800" width="400" height="204" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;From the beginning it was a bit hard to discover how to really use it. I went back to the movie from Google IO and start repeat what they do in the movie and play a little bit with this. I really start appreciating the new way of communications.&lt;/p&gt;  &lt;p&gt;As far I’ve tested it, the core functionality works already fine. Anyway, some features didn’t work for me at all. For example &lt;em&gt;Insert Search Map&lt;/em&gt; function used the way it was shown in the movie displays always Australia. (what, in fact, is not so big surprise for me ;)). It freeze also many times .&lt;/p&gt;  &lt;p&gt;The first excitement and the real challenge will be to create my first gadget, which is basically my goal. But that must be postponed since the main app is not ready yet. &lt;/p&gt;  &lt;p&gt;What are my doubts about it is that it may be difficult to use for a “not-computer” people. I mean the whole idea is completely new, and is great, but it is also difficult to compare to anything else and it may be difficult to understand, especially beyond the basic functionality. And a big part of the power of Google Wave lies in extensions that, at this moment, are far to tricky to use.&lt;/p&gt;  &lt;p&gt;However, the real value of Google Wave is a team work/communications which is difficult to discover without “a team” and my contact list remain empty (not to mention 3 robots which I played with) That’s why I wish to invite everyone who has a wave account, want to test it and has the same problem. Please, let me know by sending a comment here or e-mail. And I have to return to the cake…&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-2853717794415359611?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/2853717794415359611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/08/wow-i-got-google-wave-sandbox-account.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/2853717794415359611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/2853717794415359611'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/08/wow-i-got-google-wave-sandbox-account.html' title='WOW !! I got Google Wave sandbox account.'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_C4LysrTfKdY/SpLKnOz-TiI/AAAAAAAAANk/31nMNBK3l8E/s72-c/Bez%20nazwy_thumb%5B5%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-727901706129553957</id><published>2009-07-30T20:24:00.001+01:00</published><updated>2010-11-18T17:49:50.869Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='CakePHP 1.2'/><title type='text'>Cake PHP 1.2 - Applying CSS to forms.</title><content type='html'>&lt;p&gt;Today I will explain in a nutshell how to apply a css style to a form generated by the &lt;a href="http://book.cakephp.org/view/182/Form" target="_blank"&gt;Form Helper&lt;/a&gt;. My form is very simple and serves as a registration form. You can find how to create a model and a controller for such form here: &lt;a href="http://planetcakephp.org/aggregator/items/1620-creating-a-community-in-five-minutes-with-cakephp" target="_blank"&gt;http://planetcakephp.org/aggregator/items/1620-creating-a-community-in-five-minutes-with-cakephp&lt;/a&gt;. Therefore, I will focus only on how to apply some css to this form.&lt;/p&gt;  &lt;p&gt;My form has only 4 required fields and is generated by the following view:&lt;/p&gt;  &lt;blockquote&gt;   &lt;pre class="brush: php"&gt;&amp;lt;div class=&amp;quot;users form&amp;quot;&amp;gt;	
&amp;lt;?php echo $form-&amp;gt;create('User', array('class'=&amp;gt;'form'));?&amp;gt;
&amp;lt;p class=&amp;quot;formtitle&amp;quot;&amp;gt;Sign Up&amp;lt;/p&amp;gt;
&amp;lt;fieldset&amp;gt;
	&amp;lt;legend class=&amp;quot;formtitle&amp;quot;&amp;gt;Please complete the form below.&amp;lt;/legend&amp;gt;
	&amp;lt;?php
		echo $form-&amp;gt;input('username',  array( 
			'label' =&amp;gt; 'Login', 
			'div'=&amp;gt;'formfield', 
			'error' =&amp;gt; array(
				'wrap' =&amp;gt; 'div', 
				'class' =&amp;gt; 'formerror'
				)
			));
		echo $form-&amp;gt;input('password',  array( 
			'label' =&amp;gt; 'Password', 
			'div'=&amp;gt;'formfield', 
			'error' =&amp;gt; array(
				'wrap' =&amp;gt; 'div', 
				'class' =&amp;gt; 'formerror'
				)
			));
		echo $form-&amp;gt;input('password_confirm', array(
			'label' =&amp;gt; 'Confirm password', 
			'type'=&amp;gt;'password', 
			'div'=&amp;gt;'formfield', 
			'error' =&amp;gt; array(
				'wrap' =&amp;gt; 'div', 
				'class' =&amp;gt; 'formerror'
				)
			));
		echo $form-&amp;gt;input('name',  array( 
			'label' =&amp;gt; 'Name', 
			'div'=&amp;gt;'formfield', 
			'error' =&amp;gt; array(
				'wrap' =&amp;gt; 'div', 
				'class' =&amp;gt; 'formerror'
				)
			));
		echo $form-&amp;gt;input('surname',  array( 
			'label' =&amp;gt; 'Surname', 
			'div'=&amp;gt;'formfield', 
			'error' =&amp;gt; array(
				'wrap' =&amp;gt; 'div', 
				'class' =&amp;gt; 'formerror'
				)
			));
		echo $form-&amp;gt;input('email',  array( 
			'label' =&amp;gt; 'E-mail', 
			'div'=&amp;gt;'formfield', 
			'error' =&amp;gt; array(
				'wrap' =&amp;gt; 'div', 
				'class' =&amp;gt; 'formerror'
				)
			));
		echo $form-&amp;gt;input('city_id',  array( 
			'label' =&amp;gt; 'City', 
			'div'=&amp;gt;'formfield', 
			'error' =&amp;gt; array(
				'wrap' =&amp;gt; 'div', 
				'class' =&amp;gt; 'formerror')));
	?&amp;gt;
&amp;lt;/fieldset&amp;gt;	
&amp;lt;?php echo $form-&amp;gt;end('Submit');?&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some explanations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;To add a class to a form tag: 
    &lt;blockquote&gt;
      &lt;pre class="brush: php"&gt;$form-&amp;gt;create('User', array('class'=&amp;gt;'form')) &lt;/pre&gt;
generates: 

      &lt;pre class="brush: php"&gt;&amp;lt;form class=&amp;quot;form&amp;quot; id=&amp;quot;UserAddForm&amp;quot; method=&amp;quot;post&amp;quot; action=&amp;quot;/kultura/users/add&amp;quot;&amp;gt;&lt;/pre&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;

  &lt;li&gt;To add a class to an input: 
    &lt;blockquote&gt;
      &lt;pre class="brush: php"&gt;echo $form-&amp;gt;input('username',  array( 
			'label' =&amp;gt; 'Login', 
			'div'=&amp;gt;'formfield', 
			'error' =&amp;gt; array(
				'wrap' =&amp;gt; 'div', 
				'class' =&amp;gt; 'formerror'
				)
			));&lt;/pre&gt;
generates this: 

      &lt;pre class="brush: php"&gt;&amp;lt;div class=&amp;quot;formfield required&amp;quot;&amp;gt;
&amp;lt;label for=&amp;quot;UserUsername&amp;quot;&amp;gt;Login&amp;lt;/label&amp;gt;
&amp;lt;input name=&amp;quot;data[User][username]&amp;quot; type=&amp;quot;text&amp;quot; maxlength=&amp;quot;20&amp;quot; value=&amp;quot;&amp;quot; id=&amp;quot;UserUsername&amp;quot; /&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt;
An error in this case will appear in: 

      &lt;pre class="brush: php"&gt;&amp;lt;div class=”formerror”&amp;gt;&amp;lt;/div&amp;gt;&lt;/pre&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A sample css style may look like this:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="brush: php"&gt;.form{
	font-family: Verdana;    
	font-size:1em;
	margin:1em;
	padding:1em;	
}

.form p.formtitle{
	color: #026475;
	font-size:1.3em;
	font-weight: bold;
}

.form fieldset{
	width:40em;
	border:1px solid #FFE545;	
	background-image: url(../img/Contact.png);
	background-position: bottom right;
	background-repeat: no-repeat;
}

.form fieldset legend{
	color: #026475;
}

.formfield{
	width:30em;
	padding:5px;
}

.formfield label{
	display:block;
	float:left;
	width:12em;
	padding:1px;
	color:#C2A34F;
	text-align:right;
}

.formfield input, .formfield  select{
	padding:0.15em;
	width:14em;
	border:1px solid #ddd;
	background:#FEFBAF;
	
	font-family: Verdana;    
	font-size:1em;
	
	-moz-border-radius:0.4em;
	-khtml-border-radius:0.4em;
}

.formfield input:hover, input:focus {
	border-color:#c5c5c5;
	background:#f6f6f6;
} 

.required input {
	border:1px solid #FBB829;
}

.form .submit input{
	font-family: Verdana;    
	font-size:1em;
	margin-top: 0.3em;
}

.formerror{
	position:relative;
	left:12.1em;
	color:#FBB829;
}&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;The result:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_C4LysrTfKdY/SnHzaikcRBI/AAAAAAAAAMs/7hGro_emkFE/s1600-h/nazwy%5B5%5D.png"&gt;&lt;img style="display: block; float: none; margin-left: auto; margin-right: auto" title="nazwy" alt="nazwy" src="http://lh5.ggpht.com/_C4LysrTfKdY/SnHzbYfiU0I/AAAAAAAAAMw/DLutdnGnDjA/nazwy_thumb%5B3%5D.png?imgmax=800" width="456" height="318" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;More interesting sources about how to use css with forms:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://www.smashingmagazine.com/2006/11/11/css-based-forms-modern-solutions/" target="_blank"&gt;http://www.smashingmagazine.com/2006/11/11/css-based-forms-modern-solutions/&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://sixrevisions.com/user-interface/25-stylish-examples-of-web-forms/" target="_blank"&gt;http://sixrevisions.com/user-interface/25-stylish-examples-of-web-forms/&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://www.sitepoint.com/article/fancy-form-design-css/" target="_blank"&gt;http://www.sitepoint.com/article/fancy-form-design-css/&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Very interesting article about forms design patterns:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://www.smashingmagazine.com/2008/07/04/web-form-design-patterns-sign-up-forms/?cp=9" target="_blank"&gt;http://www.smashingmagazine.com/2008/07/04/web-form-design-patterns-sign-up-forms/?cp=9&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and, b.t.w., some hint how to do CakePHP forms more secure using Security component:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://teknoid.wordpress.com/2008/11/05/make-your-cakephp-forms-a-lot-more-secure/"&gt;http://teknoid.wordpress.com/2008/11/05/make-your-cakephp-forms-a-lot-more-secure/&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-727901706129553957?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/727901706129553957/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/07/cake-php-applying-css-to-forms.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/727901706129553957'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/727901706129553957'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/07/cake-php-applying-css-to-forms.html' title='Cake PHP 1.2 - Applying CSS to forms.'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_C4LysrTfKdY/SnHzbYfiU0I/AAAAAAAAAMw/DLutdnGnDjA/s72-c/nazwy_thumb%5B3%5D.png?imgmax=800' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-1255764248699675356</id><published>2009-07-21T18:23:00.001+01:00</published><updated>2010-11-18T17:28:39.740Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='CakePHP 1.2'/><title type='text'>CakePHP 1.2 - dynamic application’s homepage – another approach.</title><content type='html'>&lt;p&gt;One of the thing a webmaster has to deal with is to create a main page of a website. It was also my recent problem. I needed to create a prototype of app’s main page that should include some logo, some menu, the newest events (posts with event info added by users), login form and some footer. More or less such prototype:&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;a href="http://lh3.ggpht.com/_C4LysrTfKdY/SmX5ltQ3TXI/AAAAAAAAAMA/Zg5bz4JRjz8/s1600-h/1%5B14%5D.jpg"&gt;&lt;img style="display: block; float: none; margin-left: auto; margin-right: auto" title="1" alt="1" src="http://lh4.ggpht.com/_C4LysrTfKdY/SmX5mUutw-I/AAAAAAAAAME/eUFdUxg0cKs/1_thumb%5B10%5D.jpg?imgmax=800" width="240" height="138" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Some ideas that I found on Internet were:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;to extend Pages Controller or, &lt;/li&gt;    &lt;li&gt;replace the default route to point to another page. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;More about the above here:    &lt;br /&gt;&lt;a href="http://teknoid.wordpress.com/2008/11/17/get-yourself-a-new-home-alternative-to-homectp/" target="_blank"&gt;http://teknoid.wordpress.com/2008/11/17/get-yourself-a-new-home-alternative-to-homectp/&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://www.phpfreaks.com/forums/index.php?topic=240370.0" target="_blank"&gt;http://www.phpfreaks.com/forums/index.php?topic=240370.0&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://www.phpfreaks.com/forums/index.php?topic=240370.0" target="_blank"&gt;http://www.phpfreaks.com/forums/index.php?topic=240370.0&lt;/a&gt;     &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;I chose another solutions: &lt;strong&gt;the elements&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;First off all we need to have some basic functionality. In my case a basic EventsController and UsersController. First step is to create a layout. It is usual that a website uses at least two layouts. One for a home page and another one (or more) for subpages. &lt;/p&gt;  &lt;p&gt;I called my layouts: &lt;em&gt;mainpage.ctp&lt;/em&gt; for the main and &lt;em&gt;default.ctp &lt;/em&gt;for the rest&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;To define a layout for a page we have to go to the page’s controller. In my case I had to change PageController (which by default is in &lt;em&gt;cake\lib\controller&lt;/em&gt; folder):&lt;/p&gt;  &lt;blockquote&gt;   &lt;pre class="brush: php"&gt;function display() {
    $this-&amp;gt;layout = 'mainpage';
    (…)
}&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Creating a layout is as easy as creating a website. We can find sample file &lt;em&gt;default.ctp&lt;/em&gt; in c&lt;em&gt;ake/libs/view/layouts/ &lt;/em&gt;and customize it for our needs. We just have to remember about some variables that carry data from controller:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;$title_for_layout&lt;/strong&gt; – page title that is defined in controller's functions. &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;pre class="brush: php"&gt;function view($id = null) {
   $this-&amp;gt;pageTitle ='Events';
(...)
}&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;$scripts_for_layout&lt;/strong&gt; – contain external sources for example scripts or css files added by html helper. &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;$content_for_layout&lt;/strong&gt; - data gathered from controller. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To create the usual html content – meta tags, charset, form etc. we can use html helper. More about it here: &lt;a href="http://book.cakephp.org/view/206/Inserting-Well-Formatted-elements" target="_blank"&gt;http://book.cakephp.org/view/206/Inserting-Well-Formatted-elements&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now is the time to create elements. I needed four. Two for menus that are more or less static and another two dynamic. First one is a login form. Another one displays newest events on the main page. The elements are placed in &lt;em&gt;app/views/elemens/&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;menu.ctp:&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="brush: php"&gt;&amp;lt;?php echo $html-&amp;gt;link(&amp;quot;home&amp;quot;, &amp;quot;/&amp;quot;, array(), null, false); ?&amp;gt;
&amp;lt;?php echo $html-&amp;gt;link(&amp;quot;events&amp;quot;, &amp;quot;/events&amp;quot;, array(), null, false); ?&amp;gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;menufooter.ctp&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="brush: php"&gt;&amp;lt;?php echo $html-&amp;gt;link(&amp;quot;Contact Us&amp;quot;, &amp;quot;/kontakt&amp;quot;, array(), null, false); ?&amp;gt;
&amp;lt;?php echo $html-&amp;gt;link(&amp;quot;Terms of Service&amp;quot;, &amp;quot;/zasady&amp;quot;, array(), null, false); ?&amp;gt;
&amp;lt;?php echo $html-&amp;gt;link(&amp;quot;Cooperate&amp;quot;, &amp;quot;/wspolpraca&amp;quot;, array(), null, false); ?&amp;gt;
&amp;lt;?php echo $html-&amp;gt;link(&amp;quot;Advertise&amp;quot;, &amp;quot;/reklama&amp;quot;, array(), null, false); ?&amp;gt;
			
&amp;lt;?php 
echo $html-&amp;gt;link(
  $html-&amp;gt;image('cake.power.gif', array('alt'=&amp;gt; __(&amp;quot;CakePHP: the rapid development php framework&amp;quot;, true),   'border'=&amp;gt;&amp;quot;0&amp;quot;)),
  'http://www.cakephp.org/',
  array('target'=&amp;gt;'_blank'), null, false);?&amp;gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first two are easy and there is nothing to explain.&lt;/p&gt;

&lt;p&gt;For user authentication I used Auth Component (&lt;a href="http://book.cakephp.org/view/172/Authentication" target="_blank"&gt;http://book.cakephp.org/view/172/Authentication&lt;/a&gt;). The default login action is &lt;em&gt;users/login&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;login.ctp&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="brush: php"&gt;&amp;lt;?php
$session-&amp;gt;flash();    
$session-&amp;gt;flash('auth');
?&amp;gt;
&amp;lt;?php  
if(!$session-&amp;gt;check('Auth.User')){
	echo &amp;quot;&amp;lt;p&amp;gt;Please log in.&amp;lt;/p&amp;gt;&amp;quot;;
	echo $form-&amp;gt;create('User', array('action' =&amp;gt; 'login'));    
	echo $form-&amp;gt;input('username');    
	echo $form-&amp;gt;input('password');    
	echo $form-&amp;gt;end('Login');
	}
else{
	echo &amp;quot;&amp;lt;p&amp;gt;Hello &amp;quot;.$session-&amp;gt;read('Auth.User.name').&amp;quot;&amp;lt;/p&amp;gt;&amp;quot;;
	echo $html-&amp;gt;link(&amp;quot;logout&amp;quot;, &amp;quot;/users/logout&amp;quot;, array(), null, false);
}
?&amp;gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;The last element – &lt;em&gt;newest.ctp&lt;/em&gt; - must pick up some data from &lt;em&gt;EventsController&lt;/em&gt;. For that I created a function in the controller that will provide the data for the element.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="brush: php"&gt;function main_show_newest(){
		$events = $this-&amp;gt;Event-&amp;gt;find('all', array('order' =&amp;gt; array('Event.insert_date ASC'),'limit' =&amp;gt; 3));
		return $events;
	}&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then in the element we use &lt;strong&gt;$this-&amp;gt;requestAction('events/main_show_newest')&lt;/strong&gt; to request data from the controller.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;newest.ctp&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="brush: php"&gt;&amp;lt;?php $events = $this-&amp;gt;requestAction('events/main_show_newest');?&amp;gt;

&amp;lt;div id=&amp;quot;newest&amp;quot;&amp;gt;
&amp;lt;h1&amp;gt;&amp;lt;?php echo __(&amp;quot;Newest events around......&amp;quot;) ?&amp;gt;&amp;lt;/h1&amp;gt;

&amp;lt;?php foreach($events as $event): ?&amp;gt;
&amp;lt;ul&amp;gt;
  &amp;lt;li&amp;gt;
   &amp;lt;div class=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;?php echo $event['Event']['name']; ?&amp;gt;&amp;lt;/div&amp;gt;
   &amp;lt;div class=&amp;quot;date&amp;quot;&amp;gt;&amp;lt;?php echo $event['Event']['starting_date']; ?&amp;gt;-&amp;lt;?php echo $event['Event']['end_date']; ?&amp;gt;&amp;lt;/div&amp;gt;
   &amp;lt;?php echo $event['Event']['description']; ?&amp;gt;
   &amp;lt;?php echo $html-&amp;gt;link(&amp;quot;more&amp;quot;, array( 'controller' =&amp;gt; 'events', 'action'=&amp;gt;'view', 'id'=&amp;gt;$event['Event']['id']), null, false); ?&amp;gt;
  &amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;?php endforeach; ?&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is also another possibility. In controller we use simply &lt;em&gt;$this-&amp;gt;paginate()&lt;/em&gt; and then in the element &lt;em&gt;$this-&amp;gt;requestAction('events/main_show_newest/sort:insert_date/direction:asc/limit:3').&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To include an element menu.ctp to the layout use &lt;em&gt;$this-&amp;gt;element('menu').&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The full mainpage layout:&lt;/p&gt;
&lt;em&gt;mainpage.ctp&lt;/em&gt; 

&lt;blockquote&gt;
  &lt;pre class="brush: php"&gt;&amp;lt;?php echo $html-&amp;gt;docType(); ?&amp;gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;

&amp;lt;head&amp;gt;
&amp;lt;?php echo $html-&amp;gt;charset(); ?&amp;gt;
&amp;lt;title&amp;gt;	Kultura.info.pl - &amp;lt;?php echo $title_for_layout; ?&amp;gt;&amp;lt;/title&amp;gt;
	
&amp;lt;?php
 echo $html-&amp;gt;meta('description','Best event tracker ever!');
 echo $html-&amp;gt;meta('keywords', 'event, events');
 echo $html-&amp;gt;css('kultura.generic');
 echo $scripts_for_layout;
?&amp;gt;
	
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;div id=&amp;quot;container&amp;quot;&amp;gt;

&amp;lt;div id=&amp;quot;header&amp;quot;&amp;gt;
&amp;lt;?php 
echo $html-&amp;gt;image('logo.jpg', array('alt'=&amp;gt; __(&amp;quot;kultura.info.pl Strona główna&amp;quot;, true), 'border'=&amp;gt;&amp;quot;0&amp;quot;)); ?&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;div id=&amp;quot;menu&amp;quot;&amp;gt;
&amp;lt;?php echo $this-&amp;gt;element('menu');?&amp;gt;
&amp;lt;/div&amp;gt;
		
&amp;lt;div id=&amp;quot;left&amp;quot;&amp;gt;
&amp;lt;?php echo $this-&amp;gt;element('login');?&amp;gt;
&amp;lt;/div&amp;gt;
		
&amp;lt;div id=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;?php $session-&amp;gt;flash(); ?&amp;gt;
&amp;lt;?php echo $content_for_layout; ?&amp;gt;
&amp;lt;/div&amp;gt;
		
&amp;lt;div id=&amp;quot;footer&amp;quot;&amp;gt;
&amp;lt;?php echo $this-&amp;gt;element('menufooter');?&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;/div&amp;gt;
	
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;em&gt;default.ctp&lt;/em&gt; layout at this moment has only one difference in comparison to &lt;em&gt;mainpage.ctp&lt;/em&gt; layout: it has no login form. I use it everywhere but the main page. Because I left the name &lt;em&gt;default.ctp&lt;/em&gt; for this layout I don’t need to declare or configure it anywhere.&lt;/p&gt;

&lt;p&gt;And that’s it. I hope it gives a basic overview of this concept.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-1255764248699675356?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/1255764248699675356/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/07/cakephp-dynamic-applications-homepage.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/1255764248699675356'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/1255764248699675356'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/07/cakephp-dynamic-applications-homepage.html' title='CakePHP 1.2 - dynamic application’s homepage – another approach.'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_C4LysrTfKdY/SmX5mUutw-I/AAAAAAAAAME/eUFdUxg0cKs/s72-c/1_thumb%5B10%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-3015085926487675589</id><published>2009-07-17T19:10:00.001+01:00</published><updated>2010-11-18T17:27:08.522Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='CakePHP 1.2'/><title type='text'>CakePHP 1.2 and “Cannot modify header information” warning. (Not a whitespace problem)</title><content type='html'>&lt;p&gt;Yesterday I spend too much time trying to solve following problem. While working with CakePHP, writing some login function, I need to use redirection. &lt;/p&gt;  &lt;p&gt;But the redirection didn’t work:&lt;/p&gt;  &lt;pre&gt;Cannot modify header information - headers already sent by (output started at
C:\xampp\htdocs\cool\app\controllers\users_controller.php:1)&lt;/pre&gt;

&lt;p&gt;Of course I checked all my code and then looked for some solution on Internet. The one, that repeats from page to page was that there is a white space or another character after “?&amp;gt;”.&lt;/p&gt;

&lt;p&gt;But not in my case. &lt;/p&gt;

&lt;p&gt;In my app everything start to work after I changed the encoding of the files from UTF8 to ANSI. It works also with UTF8 without BOM. It seems to be more or less obvious, but without diving into the encoding issues it is difficult to explain.&lt;/p&gt;

&lt;p&gt;And one more thing: the problem is related with PHP in general, not just CakePHP, so Cake stays blessed (so far…).&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-3015085926487675589?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/3015085926487675589/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/07/cakephp-and-cannot-modify-header.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/3015085926487675589'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/3015085926487675589'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/07/cakephp-and-cannot-modify-header.html' title='CakePHP 1.2 and “Cannot modify header information” warning. (Not a whitespace problem)'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-8071416784798176904</id><published>2009-07-17T18:30:00.001+01:00</published><updated>2010-11-18T16:19:09.196Z</updated><title type='text'>Small re-organization.</title><content type='html'>&lt;p&gt;Over last few weeks everything has changed. I didn’t even have time to eat (despite the fact is my another hobby). &lt;/p&gt;  &lt;p&gt;So far, I went into the other site of the browser and I’m working on a Web 2.0 project in CakePHP. It is a nice and useful framework, but I’m just a beginner so maybe my opinion will change. Time shrinks, and I still have a lot work to do, so keep fingers for me. &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-8071416784798176904?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/8071416784798176904/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/07/small-re-organization.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/8071416784798176904'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/8071416784798176904'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/07/small-re-organization.html' title='Small re-organization.'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-403821926219838633</id><published>2009-04-29T21:40:00.000+01:00</published><updated>2010-11-18T16:17:23.794Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='google'/><title type='text'>Google O3D - a new web standard for 3D graphics?</title><content type='html'>&lt;p&gt;Since VRLM/X3D times there was no other interesting replacement for web 3D graphics. Unfortunately VRML/X3D was also not so widely used as it was expected. Perhaps it was to innovative for its times.&lt;/p&gt;  &lt;p&gt;Around two weeks ago Google (in contribution with Khronos) released new JavaScript API for creating interactive 3D graphics applications that run directly in a browser window using a special plug-in. More information &lt;a href="http://code.google.com/intl/pl/apis/o3d/docs/techoverview.html"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;At this moment there are only few configurations that are fully supported and my old hardware is not on this list. Just to get a taste of O3D I used my friend’s computer to create a simple example with o3djs.simple utility library.&lt;/p&gt;  &lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://4.bp.blogspot.com/_C4LysrTfKdY/Sfi4UjnPZvI/AAAAAAAAACU/cPv1OpfxvV0/s1600-h/o3d1.jpg" imageanchor="1"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_C4LysrTfKdY/Sfi4UjnPZvI/AAAAAAAAACU/cPv1OpfxvV0/s200/o3d1.jpg" /&gt;&lt;/a&gt;&lt;a href="http://draft.blogger.com/"&gt;&lt;/a&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://4.bp.blogspot.com/_C4LysrTfKdY/Sfi4WhTjSvI/AAAAAAAAACc/Xh0sgVIijK0/s1600-h/o3d2.jpg" imageanchor="1"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_C4LysrTfKdY/Sfi4WhTjSvI/AAAAAAAAACc/Xh0sgVIijK0/s200/o3d2.jpg" /&gt;&lt;/a&gt;&lt;/div&gt; &lt;a href="http://thashawonderland.appspot.com/files/html/tutorial/o3d/index1.htm"&gt;example 1&lt;/a&gt; &lt;a href="http://thashawonderland.appspot.com/files/html/tutorial/o3d/index2.htm"&gt;example 2&lt;/a&gt;   &lt;p&gt;It took around a quarter to create each of above examples. O3djs.simple library is anyway only for very basic use. Despite the fact, that this library is simple and does not allow many useful functions, is a bit slow. But OK, JavaScript is slow in general.&lt;/p&gt;  &lt;p&gt;On the website there are many more advanced samples showing features that should please professionals.&lt;/p&gt;  &lt;p&gt;At the end there are good news that should gratify both basic, and advanced graphics: there is a possibility to convert contend from few programs (e.g. Autodesk 3ds Max, Maya, and Google SketchUp) using COLLADA Converter, and load it directly in o3d. &lt;/p&gt;  &lt;p&gt;Reading comments on Google o3d blog I saw many voices pro but also some against this new approach. One is sure: it is worthy of keeping track on it.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-403821926219838633?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/403821926219838633/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/04/google-o3d-new-web-standard-for-3d.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/403821926219838633'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/403821926219838633'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/04/google-o3d-new-web-standard-for-3d.html' title='Google O3D - a new web standard for 3D graphics?'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_C4LysrTfKdY/Sfi4UjnPZvI/AAAAAAAAACU/cPv1OpfxvV0/s72-c/o3d1.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-653412530313565416</id><published>2009-04-08T18:46:00.000+01:00</published><updated>2010-11-18T15:58:58.125Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='google apis'/><title type='text'>Simple geo-location with Google Maps API</title><content type='html'>&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Google Maps JavaScript API V2 is &lt;strong&gt;deprecated&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;Today I decided to do something easy and a bit effective at the same time. I chose simple geo-location of visitors using &lt;strong&gt;Google Maps Api&lt;/strong&gt;.     &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;First I will explain step-by-step, as simply and short as possible, basic issues and then, in the end, I will show full working example with (I hope) easy to understand description.&amp;#160; &lt;br /&gt;To use scripts from this tutorial you only need to be familiar with basics of HTML and general idea about object oriented programming but to fully understood or extend mentioned below scripts you should know basics of JavaScript, Ajax, and XHTML.     &lt;br /&gt;    &lt;br /&gt;Let's start. Enjoy!     &lt;br /&gt;    &lt;br /&gt;In short&lt;strong&gt; Google Ajax API&lt;/strong&gt; let you use some of google products like maps, language tools, google search or even earth your websites an easy way. Everything in advantage of Ajax.     &lt;br /&gt;More information &lt;a href="http://code.google.com/apis/ajax/" target="_blank"&gt;here&lt;/a&gt;.     &lt;br /&gt;    &lt;br /&gt;With Ajax web applications can retrieve data from the server in background (without reloading a website). To achieve this functionality AJAX uses XMLHttpRequest object. This is kind of API build in in web browser that makes possible to communicate with web server (over HTTP protocol) from user-side script (like the JavaScript). More about Ajax &lt;a href="http://en.wikipedia.org/wiki/Ajax_%28programming%29"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Let's insert a simple google map object showing location of a visitor of this page.    &lt;br /&gt;In general, using Google Ajax API you don't need to operate on &lt;i&gt;XMLHttpRequest&lt;/i&gt;object in direct way. You will get a &lt;i&gt;google&lt;/i&gt; object that can load particular module like &lt;i&gt;maps&lt;/i&gt; or search to let you use its method or properties.     &lt;br /&gt;    &lt;br /&gt;General application schema to use Google AJAX API is as follows: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;in &lt;i&gt;head&lt;/i&gt; section of you website you insert script that creates google object for you. ABCDEFG is a key of your website. How to obtain it will be shown later in details.       &lt;pre class="brush: html"&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;http://www.google.com/jsapi?key=ABCDEFG&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;
  &lt;/li&gt;

  &lt;li&gt;at this point you have already access to &lt;i&gt;google&lt;/i&gt; object. In next step (still in a page's header) we will create main script that will create and manage with module that we want to insert in the website. Basic schema of this script is as follows: 

    &lt;pre class="brush: js"&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;
   
    //first we need to load module that we are going to use, and it's version
    google.load(module, version)
   
    //next step is to create a main function that initializes object and manage     
    //its behavior in particular place on website using DOM
    function onload(){
        if (GBrowserIsCompatible()) {
           
            var map = new google.maps.Map2(document.getElementById(&amp;quot;map&amp;quot;));
            (...)
            var searchControl = new google.search.SearchControl();
            (...)
            searchControl.draw(document.getElementById(&amp;quot;searchcontrol&amp;quot;));
        }    

        //now we call the main function using callback function (it's argument is      
	//another function); this function runs only once - while a document is      
	//loading
        google.setOnLoadCallback(onload);

&amp;lt;/script&amp;gt;&lt;/pre&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Above code is only a frame and needs to be extended in order to work.&lt;/p&gt;

&lt;p&gt;How to get geo-information about a visitor? Google.load includes a property google.loader.ClientLocation that stores information about the client. The most important one is client's IP adderess and geo-loaction data besed on it. From this property we can read following information:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;i&gt;ClientLocation.latitude&lt;/i&gt; — supplies the low resolution latitude associated with the client's IP address &lt;/li&gt;

  &lt;li&gt;&lt;i&gt;ClientLocation.longitude&lt;/i&gt; — supplies the low resolution longitude associated with the client's IP address &lt;/li&gt;

  &lt;li&gt;&lt;i&gt;ClientLocation.address.city&lt;/i&gt; — supplies the name of the city associated with the client's IP address &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the IP address is not accessible, then &lt;i&gt;google.loader.ClientLocation&lt;/i&gt; is equal to NULL. 

  &lt;br /&gt;Much more detailed introduction to Google AJAX API &lt;a href="http://code.google.com/apis/maps/documentation/javascript/v2/" target="_blank"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Now the last think that we need is to know how to use Google Map API. In short, after we have loaded map module we can simply create map object (in this case &lt;i&gt;GMap2&lt;/i&gt; object) a of a given size and in a given (by element id) place on the map.&lt;/p&gt;

&lt;pre class="brush: js"&gt;var map = new GMap2(document.getElementById(&amp;quot;map&amp;quot;));&lt;/pre&gt;
In next step we need to set up this our map: 

&lt;br /&gt;

&lt;pre class="brush: js"&gt;map.setCenter(new GLatLng(lat, lon), zoom);&lt;/pre&gt;
where &lt;em&gt;lat&lt;/em&gt; and &lt;em&gt;lon&lt;/em&gt; are values of latitude and longitude and that we can easily read from google.loader.ClientLocation property. Zoom (as the name indicate) is a value of zoom that we can customize to make the map more/less detailed. 

&lt;br /&gt;The last think to do is to locate a marker in the right place: 

&lt;br /&gt;

&lt;pre class="brush: js"&gt;map.addOverlay(new GMarker(new GLatLng(lat, lon)));&lt;/pre&gt;

&lt;p&gt;Here it is important to remember that the GMarker must take as its argument GLatLng object that stores real geographical coordinates - not the coordinates of the map object. (Much more detiled introduction to Google MAP API &lt;a href="http://code.google.com/apis/maps/documentation/#AJAX_Loader" target="_blank"&gt;here&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Now let's take everything together! 
  &lt;br /&gt;At first we need to obtain the key. This can be done here: &lt;a href="http://code.google.com/apis/ajaxsearch/signup.html." target="_blanl"&gt;http://code.google.com/apis/ajaxsearch/signup.html&lt;/a&gt;. You need to have prepared an address of your website and own a google account. Remember, all your JavaSript code must be placed in head section of the website. 

  &lt;br /&gt;Once you obtain you own key you have to replace it in below script: 

  &lt;br /&gt;&lt;/p&gt;

&lt;pre class="brush: js"&gt;&amp;lt;script src='http://www.google.com/jsapi?key=KEY' type='text/javascript'/&amp;gt;
&amp;lt;script language='Javascript' type='text/javascript'&amp;gt;

//skip this in a browser that doesn't support JavaScritp
//&amp;lt;![CDATA[

//load map module version 2
google.load(&amp;quot;maps&amp;quot;, &amp;quot;2&amp;quot;);

//create the main function
function OnLoad() {
        
   //checks if user's browser is supports AJAX 
   if ((GBrowserIsCompatible())) {   
           
   //set initial values for latitude, longitude and zoom
   var lon = 0;
   var lat = 0;
   var zoom = 0;

   //if google.loader is able to discover user information...
   if(google.loader.ClientLocation!=null){

      //read user's informations to following variables
      var country = google.loader.ClientLocation.address.country;
      var region = google.loader.ClientLocation.address.region;
      var city = google.loader.ClientLocation.address.city;
      lat = google.loader.ClientLocation.latitude;
      lon = google.loader.ClientLocation.longitude;
      zoom = 5;

      var locationString = country + &amp;quot;, &amp;quot; + region+ &amp;quot;, &amp;quot; + city;    
      //and now we can insert that information into element with
      //id=&amp;quot;location&amp;quot;
      document.getElementById(&amp;quot;location&amp;quot;).innerHTML = locationString;
   }
   //otherwise print information in location div
   else{
      document.getElementById(&amp;quot;location&amp;quot;).innerHTML = &amp;quot;not supported&amp;quot;;
   }
          
   //create a map object in element with id=&amp;quot;map&amp;quot;
   var map = new GMap2(document.getElementById(&amp;quot;map&amp;quot;));
   //center map to client's geographic coordination 
   //(it they exists, otherwise use initial values)
   //the last number let u customize your zoom value
   //the grater the number, the more detailed map you will have        
   map.setCenter(new GLatLng(lat, lon), zoom);           
   //add market at visitor's location
   map.addOverlay(new GMarker(new GLatLng(lat, lon)));
  
   //customize the map
   map.setMapType(G_SATELLITE_MAP);
   map.GMap2.disableGoogleBar(); 
   }
else{ 
   //insert information into element with id=&amp;quot;location&amp;quot;
   document.getElementById(&amp;quot;location&amp;quot;).innerHTML = &amp;quot;AJAX not supported&amp;quot;;
 }
}

//pass OnLoad() function to call back function
google.setOnLoadCallback(OnLoad);

//]]&amp;gt;
&amp;lt;/script&amp;gt;&lt;/pre&gt;
That is the JavaScript code. 

&lt;br /&gt;Now the last thing to do is to create container elements on a website. These can be e.g: 

&lt;br /&gt;

&lt;pre class="brush: css"&gt;&amp;lt;div id=&amp;quot;location&amp;quot;&amp;gt;loading...&amp;lt;/div&amp;gt;&lt;/pre&gt;
for location information. And for the map: 

&lt;br /&gt;

&lt;pre class="brush: html"&gt;&amp;lt;div id=&amp;quot;map&amp;quot; style=&amp;quot;width: 180px; height: 180px; display: block;&amp;quot;&amp;gt;loading...&amp;lt;/div&amp;gt;&lt;/pre&gt;

&lt;p&gt;After &lt;i&gt;google.setOnLoadCallback(OnLoad)&lt;/i&gt; has been called (at the begging of processing our website)&amp;#160; &amp;quot;loading...&amp;quot;&amp;#160; changes to value of locationString variable and map object. All that assuming that the JavaScript is enabled in your browser and google.loader is able to achieve user location data. &lt;/p&gt;

&lt;p&gt;At this moment our geo-location should looks more or less like this: 
  &lt;br /&gt;&lt;/p&gt;

&lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://4.bp.blogspot.com/_C4LysrTfKdY/SdzgOefg7ZI/AAAAAAAAACE/hnIuADsxIrw/s1600-h/geo1.jpg" imageanchor="1"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_C4LysrTfKdY/SdzgOefg7ZI/AAAAAAAAACE/hnIuADsxIrw/s320/geo1.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;
As you can see, a Google logo and copyrights information doesn't look nice in a map of this size. Of course in any case we should not delete it (that's not so easy, as well). However, there is a way to change its appearance. In order to do so you should add some style information to your website style: 

&lt;br /&gt;

&lt;pre class="brush: css"&gt;/*TerraMetrics*/
div#map div span{
   right: 2px;
   display:block;
   font-size:9px;
}
/*help link*/
div#map div a{
   right: 2px;
   display:block;
   font-size: 9px;
}
/*Google logo*/
div#map div a img{
   position:relative;
   left: 2px;
   bottom: 140px;
   border: 2px solid #0000FF;
}&lt;/pre&gt;
You can always get the information about elements&amp;#160; you haven't create using a tool like Web Developer Toolbar for Firefox. That's the effect: 

&lt;br /&gt;

&lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://3.bp.blogspot.com/_C4LysrTfKdY/SdziBd1z7PI/AAAAAAAAACM/IH6B0LnnX0E/s1600-h/geo2" imageanchor="1"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_C4LysrTfKdY/SdziBd1z7PI/AAAAAAAAACM/IH6B0LnnX0E/s320/geo2" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;You must keep in mind that &lt;i&gt;google.loader.ClientLocation&lt;/i&gt; is only trying to guest a location based on IP address. Everything depends on what kind of Internet connection your visitor has. It may also happen that the location won't be recognized at all. Sorry. Don't be disapointed.&lt;/p&gt;

&lt;p&gt;Of course the geo-location is not the most useful element of you website. However playing with google maps is a good exercise that let you enable some more cheerful functionality of your blog or website like presenting a weather forecast or news related with visitor's location. &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-653412530313565416?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/653412530313565416/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/04/simple-geo-location-with-google-maps.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/653412530313565416'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/653412530313565416'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/04/simple-geo-location-with-google-maps.html' title='Simple geo-location with Google Maps API'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_C4LysrTfKdY/SdzgOefg7ZI/AAAAAAAAACE/hnIuADsxIrw/s72-c/geo1.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-5350335914851967276</id><published>2009-03-01T11:24:00.001Z</published><updated>2010-11-18T11:11:30.234Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>Multiple Background Images CSS3 and CSS2</title><content type='html'>Many times I wish to assign many background images with different settings to one &lt;i&gt;html&lt;/i&gt; element. For example, I need to assign one image that will always be at the bottom on the left site, another one at the top on the right and one gradient below everything.   &lt;div style="text-align: center; clear: both" class="separator"&gt;&amp;#160;&lt;/div&gt;  &lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://3.bp.blogspot.com/_C4LysrTfKdY/SapxcWARydI/AAAAAAAAAB8/pyj37_jyFC4/s1600-h/view.png" imageanchor="1"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_C4LysrTfKdY/SapxcWARydI/AAAAAAAAAB8/pyj37_jyFC4/s320/view.png" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;div style="text-align: center; clear: both" class="separator"&gt;&amp;#160;&lt;/div&gt; Despite the fact that &lt;strong&gt;CSS3&lt;/strong&gt; offers an easy way to do it, many browsers do not support it yet.   &lt;pre class="brush: css"&gt;body{ 
   margin:0; 
   padding:0; 
   border:0; 
   font-family: Verdana; 
   font-size:10px; 
   background-image:url('bg2.gif'), url('bg3.gif'), url('bg1.jpg'); 
   background-repeat: no-repeat, no-repeat, repeat-x; 
   background-position:bottom left, top right, top;
}&lt;/pre&gt;

&lt;p&gt;In this code it is important to remember that last image will be load as first. &lt;/p&gt;

&lt;p&gt;This works fine for Chrome 1.x and Safari 3.2. It works also ok for Konqueror 3.5 but it doesn’t support transparency in gif images. If one of the background elements is attached to the bottom this image is not rendered in Chrome 2 and Safari 4. It can be fixed by adding &lt;em&gt;height:100%:&lt;/em&gt; &lt;/p&gt;

&lt;pre class="brush: css"&gt;html{
    margin:0;
    padding:0;
    border:0;
    font-family: Verdana;
    font-size:10px;
    background-image:url(bg2.gif), url(bg3.gif), url(bg1.jpg);
    background-repeat: no-repeat, no-repeat, repeat-x;
    background-position: bottom left, top right, top;
    height:100%;
}&lt;/pre&gt;

&lt;p&gt;It works in Chrome 1.x, Chrome 2.x Safafi 3.2 Safari 4. An example is &lt;a href="http://thashawonderland.appspot.com/files/html/tutorial/3/index.htm"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;There is also a possibility to achieve almost the same effect with &lt;strong&gt;CSS2&lt;/strong&gt; using few layers placed one above another. &lt;/p&gt;

&lt;pre class="brush: html"&gt;&amp;lt;div id=&amp;quot;wrapper1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;wrapper2&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;wrapper3&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/pre&gt;

&lt;pre class="brush: css"&gt;#wrapper1, #wrapper2, #wrapper3{ 
   padding:0; 
   margin:0; 
   border:0; 
   position:absolute; 
   top:0px; 
   left:0px; 
   right:0px; 
   bottom:0px;
}
#wrapper1{ 
   background-image:url('bg1.jpg'); 
   background-color: #FFFFAA; 
   background-repeat:repeat-x; 
   background-attachment:fixed;
}
#wrapper2{ 
   background-image:url('bg2.gif'); 
   background-position:bottom left; 
   background-repeat:no-repeat; 
   background-attachment:fixed; }
#wrapper3{ 
   background-image:url('bg3.gif'); 
   background-position:top right; 
   background-repeat:no-repeat; 
   background-attachment:fixed;
}&lt;/pre&gt;

&lt;p&gt;With small changes this style works also with IE. &lt;/p&gt;

&lt;pre class="brush: css"&gt;#wrapper1, #wrapper2, #wrapper3{   
   width:100%;   
   height:100%;
}&lt;/pre&gt;

&lt;p&gt;A CSS2 example is &lt;a href="http://thashawonderland.appspot.com/files/html/tutorial/4/index.htm"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-5350335914851967276?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/5350335914851967276/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/03/multiple-background-images-css3-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/5350335914851967276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/5350335914851967276'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/03/multiple-background-images-css3-and.html' title='Multiple Background Images CSS3 and CSS2'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_C4LysrTfKdY/SapxcWARydI/AAAAAAAAAB8/pyj37_jyFC4/s72-c/view.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-6825695779615222776</id><published>2009-02-07T18:56:00.000Z</published><updated>2010-11-17T18:49:08.316Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>IE6 versus position:fixed layout.</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_C4LysrTfKdY/SY3wDW8Az6I/AAAAAAAAAB0/WkHrM649Zf8/s1600-h/msie8.png"&gt;&lt;/a&gt;  &lt;div&gt;Let’s go back to this post: &lt;a href="http://thasha-in-wonderland.blogspot.com/2009/02/simple-layout-using-positionfixed.html"&gt;Simple layout using position:fixed&lt;/a&gt;. Why IE6 does not support &lt;a href="http://thasha-in-wonderland.blogspot.com/2009/02/simple-layout-using-positionfixed.html"&gt;this&lt;/a&gt; site? Well, IE6 does not support &lt;i&gt;position:fixed&lt;/i&gt; and skip top, bottom, left and right properties. As a result all elements appear in their normal flow. (In some cases we can use &lt;i&gt;position:absolute&lt;/i&gt; instead &lt;i&gt;position:fixed&lt;/i&gt; but it has some constraints).&lt;/div&gt;  &lt;div&gt;&amp;#160;&lt;/div&gt;  &lt;div&gt;Anyway, there is a possibility to use another famous bug (difference in interpretation of CSS parameters) from IE5 to achieve similar layout working in IE5 and IE6.&lt;/div&gt;  &lt;div&gt;&amp;#160;&lt;/div&gt;  &lt;div&gt;Let’s start from beginning. In 1998, when IE5 appears, most of the webmasters use HTML to create web pages. Also most of the browsers could not correctly interpret CSS1 and XHTML standards. IE5 has a bug in interpretation of a size of and element (so called &lt;em&gt;box model bug&lt;/em&gt;) &lt;a href="http://en.wikipedia.org/wiki/Internet_Explorer_box_model_bug"&gt;http://en.Wikipedia.org/wiki/Internet_Explorer_box_model_bug&lt;/a&gt;. &lt;/div&gt;  &lt;div&gt;&amp;#160;&lt;/div&gt;  &lt;div&gt;In IE5 &lt;i&gt;width&lt;/i&gt; value includes also margin and padding values. Therefore, if we set &lt;i&gt;width&lt;/i&gt; parameter to 100% and the &lt;i&gt;margin&lt;/i&gt; and &lt;i&gt;padding&lt;/i&gt; to 10px then the full element &lt;i&gt;width&lt;/i&gt; will fit exactly to the window (since in other browsers which supports W3C standard the element &lt;i&gt;width&lt;/i&gt; will extend the window by 40px). &lt;/div&gt;  &lt;div&gt;This bug was fixed in IE6 but so many websites created for IE5 already existed that Microsoft decided to keep compliance with the old interpretation and enables a possibility to turn IE6 to render the CSS the way the IE5 does. The same happened with many different browsers that old versions didn’t support correctly W3C standards. The mode, when the browsers work as an old version, is called &lt;b&gt;Quirks mode&lt;/b&gt;. More about it here: &lt;a href="http://www.quirksmode.org/"&gt;http://www.quirksmode.org/&lt;/a&gt;.&lt;/div&gt;  &lt;div&gt;&amp;#160;&lt;/div&gt; &lt;di&gt;How to use quirks mode to build a layout? We can set up the &lt;i&gt;content&lt;/i&gt; layer to make it fit to the window (with and height to 100%) and set borders to the size of &lt;i&gt;menu&lt;/i&gt;, &lt;i&gt;header&lt;/i&gt; and &lt;i&gt;footer&lt;/i&gt;. Then we move this layer to the back (&lt;i&gt;z-index:-1&lt;/i&gt;) and put &lt;i&gt;header&lt;/i&gt;, &lt;i&gt;menu&lt;/i&gt; and &lt;i&gt;footer&lt;/i&gt; over it. The result will be nearly the same. We only need to make the left border the same color as menu (&lt;i&gt;menu&lt;/i&gt; won’t be stretched between &lt;i&gt;header&lt;/i&gt; and &lt;i&gt;footer&lt;/i&gt; anymore) and change positioning of &lt;i&gt;footer&lt;/i&gt; to &lt;i&gt;absolute&lt;/i&gt;.   &lt;div&gt;How to switch between the styles depending on a browser? First of all we have to assure that IE6 will turn to quirks mode. For that purpose we need to set a DOCTYPE to xhtml strict and add an xml prolog. (In this case IE7 will stay in standard mode). Then we can use conditional declaration:&lt;/div&gt;  &lt;pre class="brush: html"&gt;&amp;lt;link href=&amp;quot;style.css&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt;
&amp;lt;!--[if lte IE 6]&amp;gt;
&amp;lt;link href=&amp;quot;ie.css&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt;
&amp;lt;![endif]--&amp;gt;&lt;/pre&gt;

&lt;div&gt;Now the only difference between this layout and that one from previous post is the lack of white space.&lt;/div&gt;

&lt;div&gt;The second css file &lt;i&gt;ie.css&lt;/i&gt; will be loaded only in IE6 or lower versions. In fact, even for IE6 or IE5 both of these style files will be loaded and all properties from first file will be replaced with values from the second file. That has some advantage because we don’t need to define everything again (just the differences).&lt;/div&gt;

&lt;div&gt;The second layout and both css files are available &lt;a href="http://thashawonderland.appspot.com/files/html/tutorial/2/index.htm"&gt;here&lt;/a&gt;.&lt;/div&gt;

&lt;div&gt;Screen shots generated on &lt;a href="http://browsershots.org/"&gt;http://browsershots.org/&lt;/a&gt;&lt;/div&gt;

&lt;div&gt;
  &lt;div style="text-align: center; clear: both; font-size: smaller"&gt;IE8&lt;/div&gt;
  &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_C4LysrTfKdY/SY3wDW8Az6I/AAAAAAAAAB0/WkHrM649Zf8/s1600-h/msie8.png"&gt;&lt;img style="text-align: center; margin: 0px auto 10px; width: 320px; display: block; height: 240px; cursor: pointer" id="BLOGGER_PHOTO_ID_5300156276972507042" border="0" alt="" src="http://1.bp.blogspot.com/_C4LysrTfKdY/SY3wDW8Az6I/AAAAAAAAAB0/WkHrM649Zf8/s320/msie8.png" /&gt;&lt;/a&gt; 

  &lt;div style="text-align: center; clear: both; font-size: smaller"&gt;IE7&lt;/div&gt;
  &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_C4LysrTfKdY/SY3wDS_qhZI/AAAAAAAAABs/xd8GcuUDkTk/s1600-h/msie7.png"&gt;&lt;img style="text-align: center; margin: 0px auto 10px; width: 320px; display: block; height: 240px; cursor: pointer" id="BLOGGER_PHOTO_ID_5300156275914081682" border="0" alt="" src="http://3.bp.blogspot.com/_C4LysrTfKdY/SY3wDS_qhZI/AAAAAAAAABs/xd8GcuUDkTk/s320/msie7.png" /&gt;&lt;/a&gt; 

  &lt;div style="text-align: center; clear: both; font-size: smaller"&gt;IE6&lt;/div&gt;
  &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_C4LysrTfKdY/SY3wDEsJCtI/AAAAAAAAABk/kDk2i0yDzGw/s1600-h/msie6.png"&gt;&lt;img style="text-align: center; margin: 0px auto 10px; width: 320px; display: block; height: 240px; cursor: pointer" id="BLOGGER_PHOTO_ID_5300156272074099410" border="0" alt="" src="http://1.bp.blogspot.com/_C4LysrTfKdY/SY3wDEsJCtI/AAAAAAAAABk/kDk2i0yDzGw/s320/msie6.png" /&gt;&lt;/a&gt; 

  &lt;div style="text-align: center; clear: both; font-size: smaller"&gt;IE5.5&lt;/div&gt;
  &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_C4LysrTfKdY/SY3wDI62HTI/AAAAAAAAABc/CsTlsb4143I/s1600-h/msie55.png"&gt;&lt;img style="text-align: center; margin: 0px auto 10px; width: 320px; display: block; height: 240px; cursor: pointer" id="BLOGGER_PHOTO_ID_5300156273209515314" border="0" alt="" src="http://2.bp.blogspot.com/_C4LysrTfKdY/SY3wDI62HTI/AAAAAAAAABc/CsTlsb4143I/s320/msie55.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/di&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-6825695779615222776?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/6825695779615222776/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/02/ie6-versus-positionfixed-layout.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/6825695779615222776'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/6825695779615222776'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/02/ie6-versus-positionfixed-layout.html' title='IE6 versus position:fixed layout.'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_C4LysrTfKdY/SY3wDW8Az6I/AAAAAAAAAB0/WkHrM649Zf8/s72-c/msie8.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-1938801451664958098</id><published>2009-02-03T18:39:00.000Z</published><updated>2010-11-17T18:28:59.852Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='google earth'/><title type='text'>First look at Google Earth 5</title><content type='html'>&lt;div&gt;Yesterday Google announced a new version of Google Earth. Therefore it is a good time to play a bit with it. One of the new features that I was very curious about is &lt;b&gt;Historical Imagery&lt;/b&gt;. You can turn back the time for a moment and see how some places looked before. However, the quality of the pictures and datum to which you can go back depends on the place. For European locations it starts usually after year 2000, 1999 for London. (But we can admire Sun Francisco from 1946.)&lt;/div&gt;  &lt;div&gt;Here is an example of a building Golden Terraces in Warsaw...&lt;/div&gt;  &lt;div style="text-align: center; clear: both; font-size: smaller"&gt;19.07.02&lt;/div&gt;  &lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://4.bp.blogspot.com/_C4LysrTfKdY/SYiQ_IjFyKI/AAAAAAAAAAM/0vcJzUJXsec/s1600-h/zt19.07.02.jpg" imageanchor="1"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_C4LysrTfKdY/SYiQ_IjFyKI/AAAAAAAAAAM/0vcJzUJXsec/s320/zt19.07.02.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;/div&gt;  &lt;div style="text-align: center; clear: both; font-size: smaller"&gt;04.06.03&lt;/div&gt;  &lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://4.bp.blogspot.com/_C4LysrTfKdY/SYiRB4aKMyI/AAAAAAAAAAU/dRfoFQtBt4g/s1600-h/zt04.06.03.jpg" imageanchor="1"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_C4LysrTfKdY/SYiRB4aKMyI/AAAAAAAAAAU/dRfoFQtBt4g/s320/zt04.06.03.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;div style="text-align: center; clear: both; font-size: smaller"&gt;18.10.06&lt;/div&gt;  &lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://4.bp.blogspot.com/_C4LysrTfKdY/SYiREGvNTWI/AAAAAAAAAAc/6QKqtV1GTzs/s1600-h/zt18.10.06.jpg" imageanchor="1"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_C4LysrTfKdY/SYiREGvNTWI/AAAAAAAAAAc/6QKqtV1GTzs/s320/zt18.10.06.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;div style="text-align: center; clear: both; font-size: smaller"&gt;now&lt;/div&gt;  &lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://4.bp.blogspot.com/_C4LysrTfKdY/SYiRF3cSzdI/AAAAAAAAAAk/zbswiRvw_yw/s1600-h/zt.27.03.07.jpg" imageanchor="1"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_C4LysrTfKdY/SYiRF3cSzdI/AAAAAAAAAAk/zbswiRvw_yw/s320/zt.27.03.07.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;div&gt;Historical Imagery seems to be very interesting ,but the most famous novelty is &lt;strong&gt;Ocean View&lt;/strong&gt;. Now we can&amp;#160; dive into to the ocean, see the under sea terrain in 3D or explore new data points placed under water surface. I would recommend visiting Galapagos Region. &lt;/div&gt;  &lt;div style="text-align: center; clear: both; font-size: smaller"&gt;The last look at the island Pico...&lt;/div&gt;  &lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://2.bp.blogspot.com/_C4LysrTfKdY/SYiS3e6SduI/AAAAAAAAAAs/7A41me60Pt4/s1600-h/Acores2+%281%29.jpg" imageanchor="1"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_C4LysrTfKdY/SYiS3e6SduI/AAAAAAAAAAs/7A41me60Pt4/s320/Acores2+%281%29.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;div style="text-align: center; clear: both; font-size: smaller"&gt;...and jump&lt;/div&gt;  &lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://2.bp.blogspot.com/_C4LysrTfKdY/SYiS41mEONI/AAAAAAAAAA0/sAKEh4GPxV0/s1600-h/Acores2.jpg" imageanchor="1"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_C4LysrTfKdY/SYiS41mEONI/AAAAAAAAAA0/sAKEh4GPxV0/s320/Acores2.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;div&gt;Btw: two shots of Building 3D View from Lisbon.&lt;/div&gt;  &lt;div style="text-align: center; clear: both; font-size: smaller"&gt;Mosteiros dos Jeronimos&lt;/div&gt;  &lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://3.bp.blogspot.com/_C4LysrTfKdY/SYiW4QY7dWI/AAAAAAAAAA8/yi8WqQwZu3o/s1600-h/Mosteiros+dos+Jer%C3%B3nimos.jpg" imageanchor="1"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_C4LysrTfKdY/SYiW4QY7dWI/AAAAAAAAAA8/yi8WqQwZu3o/s320/Mosteiros+dos+Jer%C3%B3nimos.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;div style="text-align: center; clear: both; font-size: smaller"&gt;Campo Pequeno.&lt;/div&gt;  &lt;div style="text-align: center; clear: both" class="separator"&gt;&lt;a style="margin-left: 1em; margin-right: 1em" href="http://1.bp.blogspot.com/_C4LysrTfKdY/SYiW5qxw5AI/AAAAAAAAABE/_t2aAiFwOoQ/s1600-h/Campo+Pegueno.jpg" imageanchor="1"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_C4LysrTfKdY/SYiW5qxw5AI/AAAAAAAAABE/_t2aAiFwOoQ/s320/Campo+Pegueno.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;  &lt;div&gt;More information about other new features, like 3D Mars and Tourning, on &lt;a href="http://googleblog.blogspot.com/2009/02/dive-into-new-google-earth.html#links"&gt;Offiicial Google Blog&lt;/a&gt; and &lt;a href="http://google-latlong.blogspot.com/"&gt;Lat Long Blog&lt;/a&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-1938801451664958098?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/1938801451664958098/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/02/first-look-at-google-earth-5.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/1938801451664958098'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/1938801451664958098'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/02/first-look-at-google-earth-5.html' title='First look at Google Earth 5'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_C4LysrTfKdY/SYiQ_IjFyKI/AAAAAAAAAAM/0vcJzUJXsec/s72-c/zt19.07.02.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-1102029956042217738</id><published>2009-02-02T15:01:00.000Z</published><updated>2010-11-17T18:16:44.834Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>Simple layout using position:fixed</title><content type='html'>&lt;div&gt;This time I would like to introduce a nice and powerful property: &lt;i&gt;position:fixed&lt;/i&gt;. Unfortunately this property is not correctly interpreted by IE-family browsers. To fully understand how it works let’s create a layout as show in the picture below:&lt;/div&gt;  &lt;div&gt;&lt;img style="text-align: center; margin: 0px auto 10px; width: 213px; display: block; height: 184px; cursor: pointer" id="BLOGGER_PHOTO_ID_5298660795082835346" border="0" alt="" src="http://1.bp.blogspot.com/_C4LysrTfKdY/SYif62wzhZI/AAAAAAAAABU/NGs4kAhMDnI/s320/image2.jpg" /&gt;&lt;/div&gt;  &lt;div&gt;Header, footer and menu always stay at their places. Footer is always at the bottom of the browser window, header is always at the top. The only scrollable part is content. There is also a white line-space between each element.&lt;/div&gt;  &lt;div&gt;&amp;#160;&lt;/div&gt;  &lt;div&gt;This template has four regions: header, menu, content and footer. We can start by adding four &amp;lt;div&amp;gt; to the body of the page:&lt;/div&gt;  &lt;pre class="brush: html"&gt;&amp;lt;body&amp;gt;&amp;#160; &amp;lt;div id=&amp;quot;header&amp;quot;&amp;gt;header&amp;lt;/div&amp;gt;
   &amp;lt;div id=&amp;quot;menu&amp;quot;&amp;gt;menu&amp;lt;/div&amp;gt;
   &amp;lt;div id=&amp;quot;content&amp;quot;&amp;gt;content&amp;lt;/div&amp;gt;
   &amp;lt;div id=&amp;quot;footer&amp;quot;&amp;gt;footer&amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt; &lt;/pre&gt;

&lt;div&gt;Perhaps a questions crosses you mind what is the different between &amp;lt;span&amp;gt; and &amp;lt;div&amp;gt;. A &amp;lt;div&amp;gt; is a block element which means that it takes a whole line, whereas &amp;lt;span&amp;gt; is an inline element what means that you can put many of them in one line. You can change this behavior defining a &lt;i&gt;display: block|inline&lt;/i&gt; property.&lt;/div&gt;

&lt;div&gt;Now we should create a style for every region:&lt;/div&gt;

&lt;pre class="brush: css"&gt;#header {    
   background-color: #A5BEF2;
}
#menu{    
   background-color: #B9DDF9;
}
#content{    
   background-color: #E2F0FD;
}
#footer{    
   background-color: #A5BEF2;
}&lt;/pre&gt;

&lt;div&gt;At this moment our layout looks like a four stripes of different colors. Normally an element appears according to its normal flow. That means that a block element will appear below another element that was former defined in a source code. (An inline element will appear next to the previous one). 
  &lt;br /&gt;We can change this normal flow using position parameter. In this case we change to &lt;i&gt;position:fixed&lt;/i&gt;. It means that the position of an element is described by a set of coordinates &lt;i&gt;left&lt;/i&gt;, &lt;i&gt;top&lt;/i&gt;, &lt;i&gt;right&lt;/i&gt;, and &lt;i&gt;bottom&lt;/i&gt; which values are relative to the browser window.&lt;/div&gt;

&lt;div&gt;There are also few more properties to changing appearance of a single element: &lt;i&gt;width&lt;/i&gt;, &lt;i&gt;margin&lt;/i&gt;, &lt;i&gt;border&lt;/i&gt; and &lt;i&gt;padding&lt;/i&gt;.&lt;/div&gt;

&lt;div&gt;Let's start with header and footer elements. The header should start at the top and be wide for the whole page. I will also set padding to 5px.&lt;/div&gt;

&lt;pre class="brush: css"&gt;#header{    
   background-color: #A5BEF2;    
   margin: 0;    
   padding: 5px;    
   height: 40px;    
   position: fixed;    
   left: 0;    
   right: 0;    
   top: 0;
}&lt;/pre&gt;

&lt;div&gt;The footer must start at the bottom of the website, be page-wide, and 30px high.&lt;/div&gt;

&lt;pre class="brush: css"&gt;#footer{    
   background-color: #A5BEF2;    
   position: fixed;    
   height: 30px;    
   padding: 5px;    
   bottom: 0;    
   right: 0;    
   left: 0;
}&lt;/pre&gt;

&lt;div&gt;Now is the time to set-up menu. Menu is 200px wide, starts just below header (and white space) – 52px from top and reaches footer (and white space) -42px from bottom.&lt;/div&gt;

&lt;pre class="brush: css"&gt;#menu{    
   background-color: #B9DDF9;    
   margin: 0;    
   width: 200px;            
   padding: 5px;    
   border: 0;    
   position: fixed;    
   top: 52px;               
   left: 0;      
   bottom: 42px;        
}&lt;/pre&gt;

&lt;div&gt;At the end we need to shift content element to the left side of menu. It is also stretched between header and footer. The full width-size of menu is 210px and because I wish to achieve a white space between them the content element will start at 212 pixel.&lt;/div&gt;

&lt;pre class="brush: css"&gt;#content{    
   background-color: #E2F0FD;    
   margin: 0;    
   padding: 5px;    
   position: fixed;    
   top: 52px;                  
   left: 212px;           
   right: 0;             
   overflow: auto;
}&lt;/pre&gt;

&lt;div&gt;Voilà!! The main layout is done.&lt;/div&gt;

&lt;div&gt;&amp;#160;&lt;/div&gt;

&lt;div&gt;Now we can focus on some more detailed formatting. First of all we can change a font. Because we want to use the same font for the entire page we can define it for the body tag. Now I should explain few words about inheritance. In general every element that find itself inside another one inherits a style from containing element unless it is changed by its own style. If we define a font for body, it will be used for every element, unless an element has its own font defined.&lt;/div&gt;

&lt;pre class="brush: css"&gt;body{    
   font-family: Verdana;    
   font-size:10px;
}&lt;/pre&gt;

&lt;div&gt;Now we will define a big main header title and some sub-header much smaller and shifted to the left site. (Notice that in this case it’s much more suitable to use classes because they may be used for many elements.)&lt;/div&gt;

&lt;pre class="brush: html"&gt;&amp;lt;div id=&amp;quot;header&amp;quot;&amp;gt;   
   &amp;lt;div class=&amp;quot;header&amp;quot;&amp;gt;Page Header&amp;lt;/div&amp;gt;   
   &amp;lt;span class=&amp;quot;sub_header&amp;quot;&amp;gt;Some header details.&amp;lt;/span&amp;gt;
   &amp;lt;/div&amp;gt;&lt;/pre&gt;

&lt;pre class="brush: css"&gt;.header{    
   font-size: 25px;    
   text-decoration: bold;    
   color: #003666;
}&lt;/pre&gt;

&lt;div&gt;To achieve the shift effect for the submenu we should use &lt;i&gt;position:relative&lt;/i&gt;. It shifts an element relative to its normal position by the values defined in &lt;i&gt;top&lt;/i&gt;, &lt;i&gt;left&lt;/i&gt;, &lt;i&gt;right&lt;/i&gt; and &lt;i&gt;bottom&lt;/i&gt; properties. &lt;/div&gt;

&lt;pre class="brush: css"&gt;.sub_header{    
   text-decoration: bold;      
   color: #ffffff;    
   position: relative;            
   bottom: 7px;                   
   left: 45px;               
}&lt;/pre&gt;

&lt;div&gt;Now we can make a title in the main page a bit more emphasized e.g making spaces between letters.&lt;/div&gt;

&lt;pre class="brush: html"&gt;&amp;lt;div id=&amp;quot;content&amp;quot;&amp;gt;   
   &amp;lt;h1&amp;gt;Lorem ipsum&amp;lt;/h1&amp;gt;
   &amp;lt;/div&amp;gt;&lt;/pre&gt;

&lt;pre class="brush: css"&gt;h1{    
   font-size: 12px;    
   letter-spacing: 0.3cm
}&lt;/pre&gt;

&lt;div&gt;The remaining part is a menu. To create one we can use a list and modify it with CSS.&lt;/div&gt;

&lt;pre class="brush: html"&gt;&amp;lt;div id=&amp;quot;menu&amp;quot;&amp;gt;   
   &amp;lt;ul class=&amp;quot;menu&amp;quot;&amp;gt;      
   &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;Lorem ipsum&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;      
   &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;Fusce vulputate&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;      
   &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;Donec blandit&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;      
   &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;Proin nulla&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;      
   &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;Nam nibh&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;   
&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&lt;/pre&gt;

&lt;div&gt;First, we want to remove the bullets:&lt;/div&gt;

&lt;pre class="brush: css"&gt;.menu{    
   list-style-type: none;
}&lt;/pre&gt;

&lt;div&gt;Now we can customize the elements of this list:&lt;/div&gt;

&lt;pre class="brush: css"&gt;.menu li {                 
   padding: 2px;    
   margin: 2px;
}&lt;/pre&gt;

&lt;div&gt;We wish also to avoid underlining a link, but make it changing color every time a cursor is over it.&lt;/div&gt;

&lt;pre class="brush: css"&gt;.menu li a{  
   text-decoration: none;  color: #003666;
}&lt;/pre&gt;

&lt;pre class="brush: css"&gt;.menu li a:hover{  
   text-decoration: none;  color:#ffffff;
}&lt;/pre&gt;

&lt;div&gt;At this point I should explain the pseudo-classes. These are some &amp;quot;sub&amp;quot; classes of an selector that may add some special effect to an element e.g change a style of an element's child &lt;i&gt;selector:first-child&lt;/i&gt;. 

  &lt;br /&gt;One of such pseudo-classes is &lt;i&gt;:hover&lt;/i&gt;, that change a style of an element when the cursor is over it. That is very useful to define a link behavior, but you can use it also with other selectors.&lt;/div&gt;

&lt;div&gt;Now let’s add some simple formatting to the footer. It looks nice when a text alignment in a footer is on opposite site to a text alignment in a header, so in this case to the right.&lt;/div&gt;

&lt;pre class="brush: css"&gt;.footer{    
   font-size:10px;    
   text-decoration: bold;    
   color:#ffffff;     
   display:block;    
   text-align: right; 
}&lt;/pre&gt;

&lt;div&gt;Of course it is difficult to talk about an alignment of an inline element that takes only so much space as it needs for a contained element. To make an effect on &lt;i&gt;text-align&lt;/i&gt; modification the element must be a block. Of course it can be achieved using &amp;lt;div&amp;gt; element that is a block by definition, but it is always worth to assure it (adding &lt;i&gt;display:block&lt;/i&gt;)when we create a style for a class and we don’t know to what kind of element this class will be applied for.&lt;/div&gt;

&lt;div&gt;The template is ready. You can see it &lt;a href="http://thashawonderland.appspot.com/files/html/tutorial/1/index.htm"&gt;here&lt;/a&gt; .&lt;/div&gt;

&lt;div&gt;Next time I will show how to create a replacement of this layout for IE.&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-1102029956042217738?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/1102029956042217738/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/02/simple-layout-using-positionfixed.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/1102029956042217738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/1102029956042217738'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/02/simple-layout-using-positionfixed.html' title='Simple layout using position:fixed'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_C4LysrTfKdY/SYif62wzhZI/AAAAAAAAABU/NGs4kAhMDnI/s72-c/image2.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5308531346925315578.post-2279294380246693920</id><published>2009-02-01T20:59:00.000Z</published><updated>2010-11-17T18:21:49.329Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>From beginning….(HTML and CSS in a nutshell)</title><content type='html'>&lt;div&gt;I considered, for a pretty long time, what could be my firs post. Finally, I decided to start with basics which could be only HTML and CSS. If you want to be someone more than an observer on the Internet you should know how to create a simple and valid website, that will look the same in every popular browser. This task, anyway, is sometimes more difficult that it seems to be… e.g. using &lt;span style="font-style: italic"&gt;position:fixed&lt;/span&gt;. Unfortunately this simple and powerful property is not working in IE.&lt;/div&gt;  &lt;div&gt;&amp;#160;&lt;/div&gt;  &lt;div&gt;Ok, let’s start with some basics of html &amp;amp; css. In next post I will show how to create a nice and easy layout using &lt;span style="font-style: italic"&gt;position:fixed&lt;/span&gt;, and then how to create similar one, for IE, taking into consideration its all oddities.&lt;/div&gt;  &lt;div&gt;&amp;#160;&lt;/div&gt;  &lt;div&gt;Here are two useful links for absolute beginners: &lt;a href="http://www.w3schools.com/xhtml/default.asp"&gt;http://www.w3schools.com/xhtml/default.asp &lt;/a&gt;&lt;a href="http://www.w3schools.com/css/default.asp"&gt;http://www.w3schools.com/css/default.asp&lt;/a&gt;&lt;/div&gt;  &lt;div&gt;&amp;#160;&lt;/div&gt;  &lt;div&gt;A very simple website:    &lt;pre class="brush: html"&gt;&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Strict//EN&amp;quot;
&amp;quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&amp;quot;&amp;gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot; xml:lang=&amp;quot;en&amp;quot; &amp;gt; 
&amp;lt;head&amp;gt; 
&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=UTF-8&amp;quot; /&amp;gt; 
&amp;lt;meta name=&amp;quot;keywords&amp;quot; content=&amp;quot;page content&amp;quot;/&amp;gt; 
&amp;lt;meta name=&amp;quot;description&amp;quot; content=&amp;quot;page description&amp;quot;/&amp;gt; 
&amp;lt;title&amp;gt;Css basics tutorial sample&amp;lt;/title&amp;gt; 
&amp;lt;link href=&amp;quot;style.css&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt; 
&amp;lt;/head&amp;gt; 
&amp;lt;body&amp;gt;   
&amp;lt;/body&amp;gt; 
&amp;lt;/html&amp;gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;div&gt;Actually displays… nothing.&amp;#160; All content that you see in a browser&amp;#160; is placed between &amp;lt;body&amp;gt;&amp;lt;/body&amp;gt; tag. There are more tags used to show the information e.g. &amp;lt;h1&amp;gt;, &amp;lt;p&amp;gt;, &amp;lt;div&amp;gt;, and &amp;lt;span&amp;gt;. Some of them will be described later.&lt;/div&gt;

&lt;div&gt;First of all you should declare document’s type and dtd. 
  &lt;pre class="brush: html"&gt;&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Strict//EN&amp;quot;
&amp;quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&amp;quot;&amp;gt; &lt;/pre&gt;
Here you have more declarations and explanations: &lt;a href="http://www.w3.org/QA/2002/04/valid-dtd-list.html"&gt;http://www.w3.org/QA/2002/04/valid-dtd-list.html &lt;/a&gt;The real document starts with &amp;lt;html&amp;gt; tag and everything must be included between &amp;lt;html&amp;gt;&amp;lt;/html&amp;gt;. Head includes some configurations and information for indexing engines, for example: 

  &lt;pre class="brush: html"&gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=UTF-8&amp;quot; /&amp;gt; &lt;/pre&gt;
tells a browser that the website uses UTF-8 encoding (more encodings for example here: &lt;a href="http://www.w3schools.com/tags/ref_charactersets.asp"&gt;http://www.w3schools.com/tags/ref_charactersets.asp&lt;/a&gt;) 

  &lt;pre class="brush: html"&gt;&amp;lt;meta name=&amp;quot;keywords&amp;quot; content=&amp;quot;page content&amp;quot;/&amp;gt;&lt;/pre&gt;
- keywords that search engine should use to index your website (at least that was the idea few years ago) 

  &lt;pre class="brush: html"&gt;&amp;lt;meta name=&amp;quot;description&amp;quot; content=&amp;quot;page description&amp;quot;/&amp;gt;&lt;/pre&gt;
- that is short description of a website, it is also good to have, because it may appear in search results 

  &lt;pre class="brush: html"&gt;&amp;lt;title&amp;gt;...&amp;lt;/title&amp;gt; &lt;/pre&gt;
- this is the website title that appears in a browser's toolbar 

  &lt;pre class="brush: html"&gt;&amp;lt;link href=&amp;quot;style.css&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt;&lt;/pre&gt;
- a link to cascade style sheet file (more about it below).&lt;/div&gt;

&lt;div&gt;&amp;#160;&lt;/div&gt;

&lt;div&gt;A single &amp;quot;style&amp;quot; is build as follows: 
  &lt;pre class="brush: css"&gt;selector {property: value}&lt;/pre&gt;
A selector can be: 

  &lt;ul&gt;
    &lt;li&gt;existing html tag: 
      &lt;pre class="brush: css"&gt;p {font-size: 10px}&lt;/pre&gt;
    &lt;/li&gt;

    &lt;li&gt;a general class: 
      &lt;pre class="brush: js"&gt;.big {font-size: 20px} &amp;lt;div class=&amp;quot;big&amp;quot;&amp;gt;Big font&amp;lt;/div&amp;gt;&amp;lt;p class=&amp;quot;big&amp;quot;&amp;gt;Big font&amp;lt;/div&amp;gt;&lt;/pre&gt;
    &lt;/li&gt;

    &lt;li&gt;a class of a particular tag: 
      &lt;pre class="brush: css"&gt;p.right {text-align: right} &amp;lt;p class=&amp;quot;big&amp;quot;&amp;gt;Big font&amp;lt;/p&amp;gt;&lt;/pre&gt;
    &lt;/li&gt;

    &lt;li&gt;id: 
      &lt;pre class="brush: css"&gt;#green{color:#006600} &amp;lt;p id=&amp;quot;green&amp;quot;&amp;gt;i'm green&amp;lt;/p&amp;gt;&lt;/pre&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
There is one important difference between id and class. Id of a given name can be use only once on one site. Therefore they can be used e.g. to build a layout. A given class can be used with many tags within one site, therefore it is very useful for formatting. If you find it may have sense, you can also use them together: 

  &lt;pre class="brush: html"&gt;&amp;lt;p class=&amp;quot;big&amp;quot; id=&amp;quot;green&amp;quot;&amp;gt;big&amp;amp;green&amp;lt;/p&amp;gt;&lt;/pre&gt;
There are three ways to insert a style to a website. 

  &lt;ul&gt;
    &lt;li&gt;in head section of the website: 
      &lt;pre class="brush: html"&gt;&amp;lt;style type=&amp;quot;text/css&amp;quot; &amp;gt; 
  hr {color: sienna}
  p {margin-left: 20px}
  body {background-image: url(&amp;quot;images/back40.gif&amp;quot;)}
&amp;lt;/style&amp;gt; 
     &lt;/pre&gt;
    &lt;/li&gt;

    &lt;li&gt;or as a link from external file, also in head section (I mentioned it before): 
      &lt;pre class="brush: html"&gt;&amp;lt;link href=&amp;quot;style.css&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt; &lt;/pre&gt;
    &lt;/li&gt;

    &lt;li&gt;or direct: 
      &lt;pre class="brush: html"&gt;&amp;lt;p style=&amp;quot;color: red&amp;quot;&amp;gt;This is a paragraph&amp;lt;/p&amp;gt;&lt;/pre&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;div&gt;That’s the basic. Now the goal is to create a layout. This will be explained next time.&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5308531346925315578-2279294380246693920?l=thasha-in-wonderland.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thasha-in-wonderland.blogspot.com/feeds/2279294380246693920/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/02/from-beginninghtml-and-css-in-nutshell.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/2279294380246693920'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5308531346925315578/posts/default/2279294380246693920'/><link rel='alternate' type='text/html' href='http://thasha-in-wonderland.blogspot.com/2009/02/from-beginninghtml-and-css-in-nutshell.html' title='From beginning….(HTML and CSS in a nutshell)'/><author><name>thasha</name><uri>http://www.blogger.com/profile/02441036254292652463</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_C4LysrTfKdY/SkznP70nWZI/AAAAAAAAAG8/5bs1z-2lso4/S220/avatar1.jpg'/></author><thr:total>0</thr:total></entry></feed>
