<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>Kenneth Falck's Blog</title><link>http://kfalck.net/</link><description /><language>en-us</language><lastBuildDate>Tue, 31 Aug 2010 17:43:25 +0300</lastBuildDate><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/kennu" /><feedburner:info uri="kennu" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item><title>Git push -varmuuskopiointi
</title><link>http://feedproxy.google.com/~r/kennu/~3/W4_BO__2cpg/git-push-varmuuskopiointi</link><description>&lt;p&gt;Versiohallinnan varmuuskopiointi on perinteisesti hankalaa. Esimerkiksi Subversion käyttää keskitettyjä repositoryja, jotka muistuttavat ominaisuuksiltaan tietokantoja. Tietokantojakin on vaikea varmuuskopioida niiden ollessa jatkuvassa käytössä. Tätä varten Subversionissa on erillinen komento "svnadmin hotcopy", jolla repositorysta voi tehdä kopion varmuuskopiointia varten.&lt;/p&gt;

&lt;p&gt;Git on puolestaan luonteeltaan hajautettu, joten varmuuskopiointi on helppo toteuttaa normaalilla push-toiminnallisuudella. Itse rakensin hiljattain järjestelmän, joka muodostuu seuraavista osista:&lt;/p&gt;

&lt;p&gt;&lt;ol&gt;&lt;li&gt; Keskitetty varmuuskopiointipalvelin, jossa on yhteinen käyttäjätunnus ja hakemisto varmuuskopioiduille repositoryille.&lt;/li&gt;&lt;li&gt;Joukko muita palvelimia, joilla sijaitsee paikallisia Git-repositoryja erilaisten projektien tarpeiden mukaan.&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;

&lt;p&gt;Kuhunkin varmuuskopioitavaan Git-repositoryyn lisätään vakioitu backup-remote:&lt;/p&gt;

&lt;p&gt;&lt;div class="code"&gt;&lt;pre&gt;git remote add backup ssh://xxx@yyy.zzz/backup/project.git
&lt;/pre&gt;&lt;/div&gt;

&lt;/p&gt;

&lt;p&gt;Sen jälkeen kullakin projektipalvelimella ajetaan säännöllisesti cronjobia, joka puskee repositoryjen uusimmat muutokset backup-remoteen:&lt;/p&gt;

&lt;p&gt;&lt;div class="code"&gt;&lt;pre&gt;git push backup --mirror
&lt;/pre&gt;&lt;/div&gt;

&lt;/p&gt;

&lt;p&gt;Näin on toteutettu keskitetty varmuuskopiointi ilman sen kummempia rsync- tai hotcopy-virityksiä. Uusia repositoryja on helppo lisätä varmuuskopioitavaksi samaa keskitettyä käyttäjätunnusta käyttäen. Varmuuskopiointipalvelin hoitaa ne sitten talteen nauhalle tai jonnekin muualle.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/LNuDfpEffa2HziaGgFxWdN6OR7E/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/LNuDfpEffa2HziaGgFxWdN6OR7E/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/LNuDfpEffa2HziaGgFxWdN6OR7E/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/LNuDfpEffa2HziaGgFxWdN6OR7E/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/kennu/~4/W4_BO__2cpg" height="1" width="1"/&gt;</description><author>kennu (Kenneth Falck)</author><pubDate>Tue, 31 Aug 2010 17:43:25 +0300</pubDate><guid isPermaLink="false">http://kfalck.net/2010/08/31/git-push-varmuuskopiointi</guid><feedburner:origLink>http://kfalck.net/2010/08/31/git-push-varmuuskopiointi</feedburner:origLink></item><item><title>Twitterin OAuth käytössä
</title><link>http://feedproxy.google.com/~r/kennu/~3/k5w7yXY_Vag/twitterin-oauth-kaytossa</link><description>&lt;p&gt;Otin vihdoinkin oman blogini Twitter-integraatiossa käyttöön &lt;a href="http://dev.twitter.com/pages/auth"&gt;OAuth-autentikoinnin&lt;/a&gt;. OAuth on aika monimutkainen, mutta onneksi Pythonille löytyy valmis &lt;a href="http://github.com/brosner/python-oauth2"&gt;python-oauth2&lt;/a&gt;-kirjasto. Vielä helpommin Twitter-integraatio onnistuu &lt;a href="http://code.google.com/p/python-twitter/"&gt;python-twitter&lt;/a&gt;-kirjastolla. Molemmat voi asentaa kätevästi easy_installilla.&lt;/p&gt;

&lt;p&gt;Nyt status-päivityksen lähettäminen on tällainen operaatio Pythonilla:&lt;/p&gt;

&lt;p&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;twitter&lt;/span&gt;
&lt;span class="n"&gt;twitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Api&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;xxx&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;yyy&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Hello World&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/p&gt;

&lt;p&gt;Twitter on deprekoinut aiemman HTTP Basic -autentikointiin perustuvan API-rajapinnan, joka oli yksinkertainen mutta turvaton. Basic-autentikointia käyttäessä palvelussa on aina välillä katkoja, jotka aiheuttavat ikävästi virheitä, jos integraation rakentaa sillä. Jossain vaiheessa Basic-autentikointi poistunee käytöstä kokonaan.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/l24DzWH34oyJIA4VKehLOQbuVMg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/l24DzWH34oyJIA4VKehLOQbuVMg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/l24DzWH34oyJIA4VKehLOQbuVMg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/l24DzWH34oyJIA4VKehLOQbuVMg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/kennu/~4/k5w7yXY_Vag" height="1" width="1"/&gt;</description><author>kennu (Kenneth Falck)</author><pubDate>Thu, 26 Aug 2010 19:52:54 +0300</pubDate><guid isPermaLink="false">http://kfalck.net/2010/08/26/twitterin-oauth-kaytossa</guid><feedburner:origLink>http://kfalck.net/2010/08/26/twitterin-oauth-kaytossa</feedburner:origLink></item><item><title>JavaScript on luokaton kieli
</title><link>http://feedproxy.google.com/~r/kennu/~3/isJt5jKmQNY/javascript-on-luokaton-kieli</link><description>&lt;p&gt;Lueskelin juuri läpi mielenkiintoisen ja sopivan lyhyen kirjan nimeltä &lt;a href="http://www.amazon.com/JavaScript-The-Good-Parts-ebook/dp/B0026OR2ZY%3FSubscriptionId%3D0VV5KRQ553R53P1G84G2%26tag%3Dkenfalsblo-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3DB0026OR2ZY"&gt;JavaScript: The Good Parts&lt;/a&gt; (Amazonin Kindle-versio). Se suorittaa ytimekkään ruumiinavauksen JavaScript-kielelle, nostaa esiin sen hyvät puolet sekä varoittaa käyttämästä huonoja ominaisuuksia.&lt;/p&gt;

&lt;p&gt;Ajattelin käydä tässä läpi muutaman asian, jotka olivat minulle uusia tai ainakin harmaata aluetta omassa JavaScript-tuntemuksessa.&lt;/p&gt;

&lt;p&gt;&lt;h2&gt;Prototyypit vs. luokat&lt;/h2&gt;&lt;/p&gt;

&lt;p&gt;JavaScriptissä ei ole luokkia, eikä sitä kannata ajatella luokkiin perustuvana ohjelmointikielenä. Monen ohjelmoijan ensireaktio tuntuu olevan se, että otetaan käyttöön tai kehitetään oma framework, joka simuloi luokkien toimintaa.&lt;/p&gt;

&lt;p&gt;Erityisen hämäävää on JavaScriptin new-syntaksi:&lt;/p&gt;

&lt;p&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;dog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/p&gt;

&lt;p&gt;New tarkoittaa JavaScriptissä ihan eri asiaa kuin esimerkiksi Javassa tai C++:ssa. Esimerkin Dog ei ole "luokan" nimi, vaikka niin helposti ajattelisi, koska JavaScriptissä ei ole luokkia. Dog on itse asiassa sellaisen funktion nimi, jonka tehtävänä on alustaa uusi objekti. Uuden objektin perintöhierarkia taas muodostuu Dog.prototype -jäsenen kautta. Kaikki Dog-objektit voisi olla määritelty perimään animal-objekti näin:&lt;/p&gt;

&lt;p&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;noise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Unknown&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;animal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;Dog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;noise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Bark!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/p&gt;

&lt;p&gt;Tällöin "var dog = new Dog()" muodostaa uuden objektin, joka perii kaikki animal-objektin jäsenet, ja jonka omat jäsenet alustetaan Dog-funktiossa.&lt;/p&gt;

&lt;p&gt;Perintöhierarkia ei siis lainkaan perustu luokkiin (joita ei ole olemassakaan), vaan prototyypin täytyy aina olla jokin toinen objekti. Jos animal-objektiin nyt lisätään uusia ominaisuuksia, ne näkyvät heti kaikissa dog-objekteissa.&lt;/p&gt;

&lt;p&gt;Tämä lisäys tehdään nimenomaan animal-objektiin eikä Animal-funktioon. Tämän eron ymmärtäminen on vaikeaa, jos asiaa yrittää hahmottaa luokkahierarkiana.&lt;/p&gt;

&lt;p&gt;&lt;h2&gt;Funktiot ja closuret muuttujien piilottajina&lt;/h2&gt;&lt;/p&gt;

&lt;p&gt;Luokattomuuden myötä JavaScriptissä ei myöskään ole perinteistä public/protected/private-erottelua objektien jäsenmuuttujille. Kaikki jäsenet ovat "public"-tyyppisiä, eli niitä voi tarkastella objektien ulkopuolelta vapaasti.&lt;/p&gt;

&lt;p&gt;Tämä on omasta mielestäni ihan hyvä asia, koska koodia voi silloin muokata ja virittää aika vapaasti. Joskus suojaamiselle on kuitenkin tarvetta, kun halutaan pakottaa esimerkiksi tietty API-rajapinta tai välttää joitakin tietoturvaongelmia.&lt;/p&gt;

&lt;p&gt;Onneksi JavaScriptin funktiot ovat closureihin yhdistettynä erittäin tehokkaita apuvälineitä muuttujien piilottamisessa. Funktion sisällä määritelty muuttuja on täysin suojassa ulkopuoliselta maailmalta.&lt;/p&gt;

&lt;p&gt;Aiempaa esimerkkiä jatkaakseni Dog-objektilla voi olla oma "my"-muuttujansa, joka ei näy objektin ulkopuolelle, mutta jota kaikki sen metodit voivat käyttää:&lt;/p&gt;

&lt;p&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;Dog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;my&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;my&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;my&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}();&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/p&gt;

&lt;p&gt;Tässä on siis jippona käyttää yhtä ylimääräistä function()-määritelyä, jonka sisällä kaikki muut funktiot määritellään. Viimeisellä rivillä tuota ylimääräistä funktiota kutsutaan ()-operaattorilla, jolloin Dog saa arvokseen sen palauttaman varsinaisen funktion.&lt;/p&gt;

&lt;p&gt;Funktioiden käyttäminen tällä tavoin monitasoisesti lienee tuttua Lisp-sukuisten funktionaalisten kielten ohjelmoijille, mutta C++/Java-taustan omaaville tämä voi vaatia hieman pohtimista, ennen kuin idea avautuu kunnolla.&lt;/p&gt;

&lt;p&gt;&lt;h2&gt;Puolipisteet rivien lopussa&lt;/h2&gt;&lt;/p&gt;

&lt;p&gt;Puolipisteet ovat JavaScriptissä periaatteessa vapaaehtoisia rivien lopuissa. Kieltä ei ole kuitenkaan suunniteltu niin, että sääntö niiden poisjättämisestä olisi kovin helppo hahmottaa yksiselitteisesti.&lt;/p&gt;

&lt;p&gt;Esimerkiksi return-lause voi yllättäen toimia eri tavalla kuin kuvittelisi:&lt;/p&gt;

&lt;p&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;...&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;noise&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;...&amp;#39;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/p&gt;

&lt;p&gt;Tuossa esimerkissä funktio palauttaa arvon undefined, koska returnin perään ilmestyy automaattinen puolipiste rivinvaihdon yhteydessä. Lause pitää siis kirjoittaa tässä muodossa:&lt;/p&gt;

&lt;p&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;...&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;noise&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;...&amp;#39;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/p&gt;

&lt;p&gt;Itse olen päättänyt olla luottamatta automaattisiin puolipisteisiin ja laitan mieluummin puolipisteen jokaisen rivin loppuun. Silloin on ainakin selkästi nähtävissä, mitä lauseen on tarkoitus tehdä, ja virhetilanteessa se on helppo korjata.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/GeKn0qjMpZTjd4eydEb37HeI1Ag/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/GeKn0qjMpZTjd4eydEb37HeI1Ag/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/GeKn0qjMpZTjd4eydEb37HeI1Ag/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/GeKn0qjMpZTjd4eydEb37HeI1Ag/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/kennu/~4/isJt5jKmQNY" height="1" width="1"/&gt;</description><author>kennu (Kenneth Falck)</author><pubDate>Wed, 25 Aug 2010 15:47:55 +0300</pubDate><guid isPermaLink="false">http://kfalck.net/2010/08/25/javascript-on-luokaton-kieli</guid><feedburner:origLink>http://kfalck.net/2010/08/25/javascript-on-luokaton-kieli</feedburner:origLink></item><item><title>If your Chromium OS image doesn&amp;#39;t boot
</title><link>http://feedproxy.google.com/~r/kennu/~3/F11nw4zWQD8/if-your-chromium-os-image-doesnt-boot</link><description>&lt;p&gt;So you built a Chromium OS image and copied it to a USB stick, but it only boots to a blank screen? Try this &lt;a href="http://groups.google.com/a/chromium.org/group/chromium-os-dev/browse_thread/thread/8052531c2be3a191/9b340bae99034924"&gt; advice&lt;/a&gt; to override the root disk:&lt;/p&gt;

&lt;p&gt;- While booting, hit Esc to bring up the Linux boot menu.&lt;br /&gt;- Choose an overridden root disk by entering:&lt;br /&gt;&amp;nbsp;&amp;nbsp; boot: chromeos-usb.A root=/dev/sdc3&lt;/p&gt;

&lt;p&gt;Depending on your hardware and disk configuration, you can try sdb3, sdc3, sdd3, etc. to find the right disk. For instance, Asus EeePC 901 has two built-in SSD drives (sda and sdb) so the correct USB device is sdc3.&lt;/p&gt;

&lt;p&gt;&lt;span style="color:red"&gt;[Update]&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;You can also specify the correct root disk manually when building the USB image (inside chroot):&lt;/p&gt;

&lt;p&gt;&lt;div class="code"&gt;&lt;pre&gt;./build_image --usb_disk /dev/sdc3
&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/L2psBYWzuguUT6Qm5wMM0OZT3Bg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/L2psBYWzuguUT6Qm5wMM0OZT3Bg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/L2psBYWzuguUT6Qm5wMM0OZT3Bg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/L2psBYWzuguUT6Qm5wMM0OZT3Bg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/kennu/~4/F11nw4zWQD8" height="1" width="1"/&gt;</description><author>kennu (Kenneth Falck)</author><pubDate>Sun, 22 Aug 2010 15:01:29 +0300</pubDate><guid isPermaLink="false">http://kfalck.net/2010/08/22/if-your-chromium-os-image-doesnt-boot</guid><feedburner:origLink>http://kfalck.net/2010/08/22/if-your-chromium-os-image-doesnt-boot</feedburner:origLink></item><item><title>OpenGL:ää aloittelemassa
</title><link>http://feedproxy.google.com/~r/kennu/~3/8Z0HbSsmAsk/openglaa-aloittelemassa</link><description>&lt;p&gt;Olen tänä kesänä lueskellut &lt;a href="http://www.amazon.co.uk/OpenGL-SuperBible-Comprehensive-Tutorial-Reference/dp/0321712617%3FSubscriptionId%3D0VV5KRQ553R53P1G84G2%26tag%3Dkenfalsblo-21%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D0321712617"&gt;OpenGL SuperBibleä&lt;/a&gt; ja opiskellut ihan ensimmäisiä perusteita siitä, miten 3D-sovelluksia rakennetaan. Ajattelin tiivistää tähän lyhyesti toimintaperiaatteita alkuun pääsemiseen.&lt;/p&gt;

&lt;p&gt;Mac OS X:ssä ohjelmoidessa on helpointa aloittaa käyttämällä &lt;a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSOpenGLView_Class/Reference/Reference.html"&gt;NSOpenGLView&lt;/a&gt;-näkymää. Kyseinen näkymä lisätään normaaliin tapaan Interface Builderissa omaan sovellukseen. Oletusarvoja on syytä heti muuttaa kahdesta propertystä:&lt;/p&gt;

&lt;p&gt;&lt;ul&gt;&lt;li&gt;Depth: 24-bit (tarvitaan syvyystarkistukseen, joka piilottaa objektien näkymättömissä olevat pinnat)&lt;/li&gt;&lt;li&gt;Buffer: [x] Double Buffer (normaali kaksoispuskurointi sulavaa animointia varten)&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;

&lt;p&gt;Tämän jälkeen on vielä tarpeen tehdä oma luokka, joka periytyy NSOpenGLView-luokasta. Sen nimi voi olla vaikka MyOpenGLView. Periytyminen tehdään normaaliin tapaan luomalla Xcodeen uusi luokka .h- ja .m-tiedostoineen ja määrittelemällä Interface Builderissa lisätyn NSOpenGLView-näkymän luokaksi MyOpenGLView.&lt;/p&gt;

&lt;p&gt;Oman luokan .h-tiedoston pitäisi näyttää suunnilleen tältä. Alkuun on lisätty muutama #import-direktiivi, joilla otetaan käyttöön glu- ja glut-apukirjastot.&lt;/p&gt;

&lt;p&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;span class="cp"&gt;#import &amp;lt;Cocoa/Cocoa.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#import &amp;lt;OpenGL/OpenGL.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#import &amp;lt;OpenGL/glu.h&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;#import &amp;lt;GLUT/GLUT.h&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;@interface&lt;/span&gt; &lt;span class="nc"&gt;MyOpenGLView&lt;/span&gt; : &lt;span class="nc"&gt;NSOpenGLView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/p&gt;

&lt;p&gt;&lt;h2&gt;Maailman alustaminen&lt;/h2&gt;&lt;/p&gt;

&lt;p&gt;Sitten päästään itse asiaan eli lisäämään 3D-toiminnallisuutta varsinaiseen .m-tiedostoon. Ensimmäiseksi kannattaa lisätä prepareOpenGL-metodi, jota kutsutaan automaattisesti sovelluksen käynnistyessä valmistelemaan ympäristö.&lt;/p&gt;

&lt;p&gt;Alustuksessa on kolme tärkeää asiaa:&lt;/p&gt;

&lt;p&gt;&lt;ul&gt;&lt;li&gt;Viewport määrittelee näkyvän ikkunan koon. Sen on syytä olla sama kuin ruudulla näkyvän ikkunan.&lt;/li&gt;&lt;li&gt;Projektiomatriisi (GL_PROJECTION) määrittelee, millaisella projektiolla 3D-maailma näytetään kaksiuloitteisella monitorilla. Yleisin on perspektiiviprojektio, joka on ihmiselle luonnollisin.&lt;/li&gt;&lt;li&gt;Model-matriisi (GL_MODEL) määrittelee miten 3D-objektit sijoittuvat maailmaan. Se alustetaan yleensä kameran sijainnilla, jonka jälkeen objektit sijoitellaan omille paikoilleen.&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;

&lt;p&gt;Kameraa määritellessä on mahdollisuus valita myös se, miten päin koordinaatiston x-, y-, ja z-akselit asettuvat ruudulle. Oletuksena x ja y kattavat monitorin pinnan ja z taas liikkuu monitorin "sisään". Omissa kokeiluissani tuntui luonnollisemmalta, että x ja y muodostavat vaakatasoisen "maanpinnan" ja z taas määrittelee objektien korkeuden pystysuunnassa.&lt;/p&gt;

&lt;p&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;prepareOpenGL&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;CGSize&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;GLfloat&lt;/span&gt; &lt;span class="n"&gt;aspectRatio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GLfloat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GLfloat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    
    &lt;span class="c1"&gt;// Pehmentämättömät värit ja syvyystestaus.&lt;/span&gt;
    &lt;span class="n"&gt;glShadeModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GL_FLAT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glEnable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GL_DEPTH_TEST&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    
    &lt;span class="c1"&gt;// Asetetaan viewport koko ikkunan kokoiseksi.&lt;/span&gt;
    &lt;span class="n"&gt;glViewport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    
    &lt;span class="c1"&gt;// Otetaan käyttöön projektiomatriisi.&lt;/span&gt;
    &lt;span class="n"&gt;glMatrixMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GL_PROJECTION&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Alustetaan projektio identiteettimatriisilla.&lt;/span&gt;
    &lt;span class="n"&gt;glLoadIdentity&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Lisätään perspektiivi, jossa silmän näkökenttä on 60 astetta.&lt;/span&gt;
    &lt;span class="n"&gt;gluPerspective&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;60.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aspectRatio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;500.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Näkyvä alue on silmästä etäisyydellä 1.0-500.0.&lt;/span&gt;
    
    &lt;span class="c1"&gt;// Otetaan käyttöön model-matriisi.&lt;/span&gt;
    &lt;span class="n"&gt;glMatrixMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GL_MODELVIEW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Alustetaan maailma identiteetimatriisilla.&lt;/span&gt;
    &lt;span class="n"&gt;glLoadIdentity&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Asetetaan kamera koordinaatteihin x=50 y=-200 z=100.&lt;/span&gt;
    &lt;span class="n"&gt;gluLookAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;50.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;200.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Kamera katsoo origoon (x=0 y=0 z=0)&lt;/span&gt;
        &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Ruudulla &amp;quot;ylös&amp;quot; osoittaa z-akselin suuntaan.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/p&gt;

&lt;p&gt;&lt;h2&gt;Maailman piirtäminen&lt;/h2&gt;&lt;/p&gt;

&lt;p&gt;Kun maailma on luotu, siihen voidaan alkaa piirtää 3D-objekteja. Tämä tapahtuu drawRect-metodissa, jota Mac OS X kutsuu automaattisesti aina, kun ikkunan sisältö pitää päivittää.&lt;/p&gt;

&lt;p&gt;Metodin alussa ollaan siinä OpenGL-matriisitilassa, johon viimeksi jäätiin. Tämän vuoksi alkuperäinen matriisitila on syytä tallentaa heti glPushMatrix()-kutsulla pinoon ja palauttaa se lopuksi sieltä glPopMatrix()-kutsulla. Vaihtoehtoisesti voi tietysti myös alustaa matriisin glLoadIdentity()-kutsulla joka kerta piirrettäessä. Tällöin kamerakin pitää määritellä aina uudelleen gluLookAt()-kutsulla.&lt;/p&gt;

&lt;p&gt;Piirtämisen alussa on myös tarpeen tyhjentää ruutu aiemmista objekteista. Tämä tehdään määrittelemällä taustaväri ja kutsumalla sitten glClear()-funktiota. Kutsulla on syytä tyhjentää samalla kertaa sekä piirrospuskuri että syvyystestauspuskuri.&lt;/p&gt;

&lt;p&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nl"&gt;drawRect:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CGRect&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;rect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Alkuperäinen matriisi (kameran sijainti) talteen.&lt;/span&gt;
    &lt;span class="n"&gt;glPushMatrix&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    
    &lt;span class="c1"&gt;// Ruudun ja syvyyspuskurin tyhjennys.&lt;/span&gt;
    &lt;span class="n"&gt;glClearColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;        
    &lt;span class="n"&gt;glClear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GL_COLOR_BUFFER_BIT&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;GL_DEPTH_BUFFER_BIT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    
    &lt;span class="c1"&gt;// Piiretään objektit ruudulle.&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    
    &lt;span class="c1"&gt;// Alkuperäisen matriisin palautus lopuksi.&lt;/span&gt;
    &lt;span class="n"&gt;glPopMatrix&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    
    &lt;span class="c1"&gt;// Päivitetään kaksoispuskuri ruudulle.&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;openGLContext&lt;/span&gt; &lt;span class="n"&gt;flushBuffer&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/p&gt;

&lt;p&gt;&lt;h2&gt;Kuution piirtäminen ruudulle&lt;/h2&gt;&lt;/p&gt;

&lt;p&gt;Edellinen esimerkki vasta tyhjensi ruudun eikä vielä piirtänyt mitään. Objekti piirretään määrittelämällä ensin mitä piirretään (kolmioita, neliöitä, polygoneja, jne.) ja antamalla sitten joukko koordinaatteja.&lt;/p&gt;

&lt;p&gt;Tämä esimerkki piirtää vihreän kuution wireframe-moodissa (GL_LINE). Paksummat viivat (glLineWidth) helpottavat ruutukaappausten ottamista.&lt;/p&gt;

&lt;p&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;span class="n"&gt;glColor3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0f&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;glPolygonMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GL_FRONT_AND_BACK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GL_LINE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;glLineWidth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;glBegin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GL_QUADS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Top &lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Bottom&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Back&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Front&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Right&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Left&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;glVertex3f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;glEnd&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/p&gt;

&lt;p&gt;&lt;h2&gt;Kuution pyörittely&lt;/h2&gt;&lt;/p&gt;

&lt;p&gt;Viimeiseksi esimerkiksi otan vielä aiemmin piirretyn kuution pyörittämisen ruudulla z-akselin (pystysuunnan) ympäri. Pyörittely tehdään glRotatef()-funktiolla, joka muuttaa model-matriisia halutun kulman verran. Oletetaan, että käytössä on globaali muuttuja GLfloat zRot, joka määrittelee rotaation asteina (0-360). Lisätään tämä rivi ennen kuution piirtämistä. Huomaa, että rivin täytyy tulla vasta glPushMatrix()-kutsun jälkeen, jotta matriisi ei sekoa.&lt;/p&gt;

&lt;p&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;span class="n"&gt;glRotatef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zRot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0f&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/p&gt;

&lt;p&gt;Sitten luodaan vielä prepareOpenGL()-metodin lopussa ajastin, joka päivittää rotaatiota 1/25 sekunnin välein ja piirtää ruudun uudelleen.&lt;/p&gt;

&lt;p&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NSTimer&lt;/span&gt; &lt;span class="nl"&gt;scheduledTimerWithTimeInterval:&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;25.0&lt;/span&gt;
    &lt;span class="nl"&gt;target:&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt; &lt;span class="nl"&gt;selector:&lt;/span&gt;&lt;span class="k"&gt;@selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;tick:&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nl"&gt;userInfo:&lt;/span&gt;&lt;span class="nb"&gt;nil&lt;/span&gt; &lt;span class="nl"&gt;repeats:&lt;/span&gt;&lt;span class="n"&gt;YES&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/p&gt;

&lt;p&gt;Itse ajastusmetodi:&lt;/p&gt;

&lt;p&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nl"&gt;tick:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NSTimer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;timer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zRot&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;360&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;zRot&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;0.5f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;zRot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt; &lt;span class="nl"&gt;setNeedsDisplay:&lt;/span&gt;&lt;span class="n"&gt;YES&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/PUBW9Q4S3kqOWaqJP6vbGRRIH4g/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/PUBW9Q4S3kqOWaqJP6vbGRRIH4g/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/PUBW9Q4S3kqOWaqJP6vbGRRIH4g/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/PUBW9Q4S3kqOWaqJP6vbGRRIH4g/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/kennu/~4/8Z0HbSsmAsk" height="1" width="1"/&gt;</description><author>kennu (Kenneth Falck)</author><pubDate>Tue, 10 Aug 2010 13:54:54 +0300</pubDate><guid isPermaLink="false">http://kfalck.net/2010/08/10/openglaa-aloittelemassa</guid><feedburner:origLink>http://kfalck.net/2010/08/10/openglaa-aloittelemassa</feedburner:origLink></item><item><title>Apple Magic Mouse paremmaksi BetterTouchToolilla
</title><link>http://feedproxy.google.com/~r/kennu/~3/IPaOfFViHN4/apple-magic-mouse-paremmaksi-bettertouchtoolilla</link><description>&lt;p&gt;Applen nykyinen &lt;a href="http://www.apple.com/fi/magicmouse/"&gt;Magic Mouse&lt;/a&gt; on kiva tuote. Se yhdistää perinteisen langattoman hiiren tuntuman kosketuslevyjen multitouch-ominaisuuksiin. Webbisivujen skrollaaminen pelkästään hiiren pintaa koskettelemalla tuntuu miellyttävältä.&lt;/p&gt;

&lt;p&gt;Sisäänrakennetuista ominaisuuksista puuttuu kuitenkin hiiren keskinappi. Oikean hiirinapin saa kyllä konfiguroitua käyttöön yhdellä rastilla asetuksista, mutta keskinappi on unohtunut kokonaan. Itse käytän kyseistä painallusta webbilinkkien avaamiseen uuteen tabiin, joten en oikein tule toimeen ilman sitä.&lt;/p&gt;

&lt;p&gt;Kaikeksi onneksi asiaan löytyy korjaus. &lt;a href="http://blog.boastr.net/"&gt;BetterTouchTool&lt;/a&gt; on ilmainen apuohjelma, jolla Magic Mouseen voi määritellä vapaasti erilaisia painalluksia ja eleitä. Itse käytin sitä lisätäkseni yksinkertaisen mappauksen "Single Finger Middle Click =&gt; Middleclick".&lt;/p&gt;

&lt;p&gt;Keskinapin simulointiin liittyy kuitenkin pieni ongelma. Magic Mousen pinta on täysin tasainen ja eri ihmisten sormet asettuvat siinä luonnostaan eri kohtiin. Itse painan keskinappia etusormella, ja painallus menee luonnostaan hiukan vasemmalle hiiren keskikohdasta.&lt;/p&gt;

&lt;p&gt;Asian voi korjata määrittelemällä BetterTouchToolin asetuksista itselleen luontevimmat rajat hiiren virtuaalisille painikkeille (ks. kuva). Reaaliaikainen multitouch-näyttö kertoo visuaalisesti, mihin kohtaan sormi (tai sormet) asettuvat hiiren päällä, ja rajat voi vetää sen mukaan.&lt;/p&gt;

&lt;p&gt;Ihan täydellinen tämä ratkaisu ei ole, sillä hiiren pinnassa edelleenkään mikään ei kerro sormille, missä kohtaa rajat menevät. Pienellä hienosäädöllä ja totuttelulla käyttö tuntuu kuitenkin luonnistuvan.&lt;/p&gt;

&lt;p&gt;PS. Kokeilin samaan tarkoitukseen aluksi erästä toista sovellusta nimeltä &lt;a href="http://magicprefs.com/"&gt;MagicPrefs&lt;/a&gt;. Se kuitenkin sekoitti hiiren kiihtyvyyden eikä huvittanut alkaa selvittelemään mistä ongelma johtui. BetterTouchTool ei ole toistaiseksi aiheuttanut vastaavaa.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Xl5v2Z2KrWNTb8BjtZ_FY7Uk8m4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Xl5v2Z2KrWNTb8BjtZ_FY7Uk8m4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Xl5v2Z2KrWNTb8BjtZ_FY7Uk8m4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Xl5v2Z2KrWNTb8BjtZ_FY7Uk8m4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/kennu/~4/IPaOfFViHN4" height="1" width="1"/&gt;</description><author>kennu (Kenneth Falck)</author><pubDate>Mon, 09 Aug 2010 17:36:54 +0300</pubDate><guid isPermaLink="false">http://kfalck.net/2010/08/09/apple-magic-mouse-paremmaksi-bettertouchtoolilla</guid><feedburner:origLink>http://kfalck.net/2010/08/09/apple-magic-mouse-paremmaksi-bettertouchtoolilla</feedburner:origLink></item><item><title>Google lopettaa Waven
</title><link>http://feedproxy.google.com/~r/kennu/~3/xlRpwQI8yQg/google-lopettaa-waven</link><description>&lt;p&gt;Official Google Blog &lt;a href="http://googleblog.blogspot.com/2010/08/update-on-google-wave.html"&gt;kirjoittaa&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;blockquote&gt;Wave has not seen the user adoption we would have liked. We don’t plan to continue developing Wave as a standalone product, but we will maintain the site at least through the end of the year and extend the technology for use in other Google projects.&lt;/blockquote&gt;&lt;/p&gt;

&lt;p&gt;Näyttäisi siis siltä, että koska Wavesta ei tullut hittiä, Google sulkee sen ja yrittää hyödyntää muissa palveluissaan ne osat, joille on käyttöä.&lt;/p&gt;

&lt;p&gt;Itse olin innokkaana kokeilemassa Wavea heti alussa ja koodasin muutamia laajennuksiakin sille. Aika pian into kuitenkin hiipui, eikä Wave oikein löytänyt paikkaansa kommunikaatiossa.&lt;/p&gt;

&lt;p&gt;Tähän vaikutti paljon se, että &lt;a href="http://docs.google.com/"&gt;Google Docs&lt;/a&gt; tarjoaa hyvät toiminnot dokumenttien ja kaaviokuvien työstämiseen usean kehittäjän kesken. Docsissa dokumentit pysyvät sitten vähän perinteisemmin organisoituina kansioihin ja integroitu chatti mahdollistaa nykyään reaaliaikaisen jutustelunkin.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/rlHgV_dKXJNpkZ5FdqJ3Fl1dnwg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/rlHgV_dKXJNpkZ5FdqJ3Fl1dnwg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/rlHgV_dKXJNpkZ5FdqJ3Fl1dnwg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/rlHgV_dKXJNpkZ5FdqJ3Fl1dnwg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/kennu/~4/xlRpwQI8yQg" height="1" width="1"/&gt;</description><author>kennu (Kenneth Falck)</author><pubDate>Thu, 05 Aug 2010 00:35:21 +0300</pubDate><guid isPermaLink="false">http://kfalck.net/2010/08/05/google-lopettaa-waven</guid><feedburner:origLink>http://kfalck.net/2010/08/05/google-lopettaa-waven</feedburner:origLink></item><item><title>F.lux siirtää vuorokausirytmin
</title><link>http://feedproxy.google.com/~r/kennu/~3/9pJEzyFFpoo/flux-siirtaa-vuorokausirytmin</link><description>&lt;p&gt;Otin &lt;a href="http://twitter.com/kennu/status/14231990155"&gt;toukokuussa&lt;/a&gt; käyttöön &lt;a href="http://www.stereopsis.com/flux/"&gt;F.luxin&lt;/a&gt;. Se on yksinkertainen sovellus, joka muuttaa näytön värilämpötilaa auringon laskiessa ja noustessa. Ilman F.luxia elimistö kuvittelee, että aurinko ei laske koskaan, jos viettää paljon aikaa iltaisinkin tietokoneen ääressä.&lt;/p&gt;

&lt;p&gt;F.lux toimii. Omalla kohdallani se on siirtänyt vuorokausirytmiä 2-4 tunnilla aikaisemmaksi. Tai oikeastaan aiemmin ei ollut mitään vuorokausirytmiä, vaan tuli tehtyä tietokoneella hommia monesti läpi yön, jos oli jokin kiinnostava projekti käynnissä. Nykyään aurinko laskee kaikilla näytöilläni klo 22 aikoihin ja klo 00 alkaa jo väsyttää. Viimeistään klo 02 nukahtaa melkein automaattisesti. Aamulla tulee sitten herättyä hämmentävän aikaisin.&lt;/p&gt;

&lt;p&gt;Huono puoli on tietysti se, että tarvittaessa on vähän vaikeampi jaksaa valvoa myöhään. Näin kesällä vaikutus tuntuu vielä korostuvan, kun on päällä jatkuva heinänuha ja antihistamiinit. Syksyllä näkee sitten, miten homma toimii auringon laskiessa jo aikaisemmin.&lt;/p&gt;

&lt;p&gt;F.luxin saa asennettua Mac-, Linux- ja Windows-koneisiin. Värilämpötilan muuttaminen voi näyttää aluksi oudolta, mutta siihen tottuu kyllä. Näytön punerrus on tavallaan samalla signaali siitä, että voi alkaa hiljalleen rentoutua iltaa kohden. Ainoat asiat, joissa värilämpötilan muutos oikeasti häiritsee, ovat kuvankäsittely ja television tai elokuvien katsominen. Silloinkin voi helposti käyttää F.luxin "Disable for an hour" -toimintoa.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/x64FZ8davV5umzQG67sN2XB0HtE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/x64FZ8davV5umzQG67sN2XB0HtE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/x64FZ8davV5umzQG67sN2XB0HtE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/x64FZ8davV5umzQG67sN2XB0HtE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/kennu/~4/9pJEzyFFpoo" height="1" width="1"/&gt;</description><author>kennu (Kenneth Falck)</author><pubDate>Mon, 02 Aug 2010 13:19:59 +0300</pubDate><guid isPermaLink="false">http://kfalck.net/2010/08/02/flux-siirtaa-vuorokausirytmin</guid><feedburner:origLink>http://kfalck.net/2010/08/02/flux-siirtaa-vuorokausirytmin</feedburner:origLink></item><item><title>Fixing a broken Windows Update on Windows 7 64-bit
</title><link>http://feedproxy.google.com/~r/kennu/~3/QM4-Um26mQo/fixing-a-broken-windows-update-on-windows-7-64-bit</link><description>&lt;p&gt;I recently noticed that my Windows 7 PC (64-bit) had not updated itself for a long time. When trying to manually run Windows Update, it would only open a dialog box saying:&lt;/p&gt;

&lt;p&gt;"Windows Update cannot currently check for updates because the service is not running"&lt;/p&gt;

&lt;p&gt;This happened despite the fact that the Windows Update service was, in fact, running and also properly configured as Automatic (Delayed Start).&lt;/p&gt;

&lt;p&gt;After unsuccesfully trying various built-in fixes in Windows 7 and also trying a downloadable Microsoft Fix It pack, I decided to run a Upgrade using the original Windows 7 installation CD. That finally fixed the problem and now Windows Update is functional again.&lt;/p&gt;

&lt;p&gt;The procedure to run an upgrade is:&lt;/p&gt;

&lt;p&gt;&lt;ul&gt;&lt;li&gt;Insert the Windows 7 installation CD.&lt;/li&gt;&lt;li&gt;Run the setup (without rebooting first).&lt;/li&gt;&lt;li&gt;Allow setup to download the latest updates.&lt;/li&gt;&lt;li&gt;Install as usual and choose to Upgrade Windows when asked.&lt;/li&gt;&lt;li&gt;You will need to re-enter the product key and re-activate.&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;

&lt;p&gt;I don't know how much of your custom settings and applications will be overwritten by this operation. I only use Windows 7 casually for gaming so I did not care.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/x7Pp1b3D5mNeEpSCKydR1miXPgs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/x7Pp1b3D5mNeEpSCKydR1miXPgs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/x7Pp1b3D5mNeEpSCKydR1miXPgs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/x7Pp1b3D5mNeEpSCKydR1miXPgs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/kennu/~4/QM4-Um26mQo" height="1" width="1"/&gt;</description><author>kennu (Kenneth Falck)</author><pubDate>Thu, 29 Jul 2010 15:01:51 +0300</pubDate><guid isPermaLink="false">http://kfalck.net/2010/07/29/fixing-a-broken-windows-update-on-windows-7-64-bit</guid><feedburner:origLink>http://kfalck.net/2010/07/29/fixing-a-broken-windows-update-on-windows-7-64-bit</feedburner:origLink></item><item><title>Syy x264-kehittäjien WebM-kritiikkiin
</title><link>http://feedproxy.google.com/~r/kennu/~3/pabbEmZWGh4/syy-x264-kehittajien-webm-kritiikkiin</link><description>&lt;p&gt;Web-videostandardeista kiinnostuneet muistanevat, että x264-kirjaston kehittäjät &lt;a href="http://x264dev.multimedia.cx/?p=377"&gt;kritisoivat vahvasti&lt;/a&gt; VP8-codeccia Googlen &lt;a href="http://kfalck.net/2010/05/19/googlen-webm-on-webin-uusi-videostandardi"&gt;julkaistua sen pari kuukautta sitten&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Nyt x264-projekti on julkaissut &lt;a href="http://mailman.videolan.org/pipermail/x264-devel/2010-July/007508.html"&gt;kaupallisen version&lt;/a&gt; kirjastostaan. Lieneekö mikään ihme, että suhtautuminen oli niin negatiivista? Raha pyörittää maailmaa.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/36zJpoyFZPrVMJbeWFobwhTggcA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/36zJpoyFZPrVMJbeWFobwhTggcA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/36zJpoyFZPrVMJbeWFobwhTggcA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/36zJpoyFZPrVMJbeWFobwhTggcA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/kennu/~4/pabbEmZWGh4" height="1" width="1"/&gt;</description><author>kennu (Kenneth Falck)</author><pubDate>Tue, 13 Jul 2010 13:28:08 +0300</pubDate><guid isPermaLink="false">http://kfalck.net/2010/07/13/syy-x264-kehittajien-webm-kritiikkiin</guid><feedburner:origLink>http://kfalck.net/2010/07/13/syy-x264-kehittajien-webm-kritiikkiin</feedburner:origLink></item></channel></rss>
