<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Athlan • Piotr Pelczar • blog programisty &#187; Internet</title>
	<atom:link href="http://athlan.pl/kategoria/internet/feed/" rel="self" type="application/rss+xml" />
	<link>http://athlan.pl</link>
	<description>Napisać kod zrozumiały dla komputera potrafi byle głupek. Dobrzy programiści tworzą kod zrozumiały dla człowieka...</description>
	<lastBuildDate>Tue, 14 Feb 2012 14:33:48 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Atak XSS na $_SERVER[&#039;HTTP_X_FORWARDED_FOR&#039;]</title>
		<link>http://athlan.pl/atak-xss-server-http-x-forwarded-for/</link>
		<comments>http://athlan.pl/atak-xss-server-http-x-forwarded-for/#comments</comments>
		<pubDate>Sat, 28 May 2011 12:40:13 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=706</guid>
		<description><![CDATA[Dziś bardzo krótko, bez zbędnych dywagacji, czyli tylko i wyłącznie o tablicy $_SERVER. Dbając o bezpieczeństwo aplikacji webowych zwraca się uwagę na wiele czynników, jakimi są SQL injections, przechwytywanie nieprawidłowych parametrów, uogólniające zapytania przepuszczające maskę % w LIKE zapytaniu do baz, XSS&#8216;y w $_POST, $_GET. I finalnie&#8230; wiele osób zapomina (a jeszcze więcej nie jest [...]]]></description>
			<content:encoded><![CDATA[<p>Dziś bardzo krótko, bez zbędnych dywagacji, czyli tylko i wyłącznie o tablicy <code>$_SERVER</code>. Dbając o bezpieczeństwo aplikacji webowych zwraca się uwagę na wiele czynników, jakimi są <em>SQL injections</em>, przechwytywanie nieprawidłowych parametrów, uogólniające zapytania przepuszczające maskę % w <em>LIKE</em> zapytaniu do baz, <em><acronym title="Cross-site scripting">XSS</acronym></em>&#8216;y w <code>$_POST</code>, <code>$_GET</code>.</p>
<p>I finalnie&#8230; wiele osób zapomina (<u>a jeszcze więcej nie jest tego świadom</u>) o możliwości wstrzyknięcia szkodliwych danych w <code>$_SERVER['HTTP_X_FORWARDED_FOR']</code>;. <u>Konsekwencje są oczywiście katastrofalne</u>.</p>
<p>O ile sama walidacja jest rzeczą wtórną, diabeł tkwi w trzech szczegółach:</p>
<ol>
<li>Rzecz trywialna, ale pamiętajmy, że w naturalnym procesie użytkowania przeglądarki, <strong>w nagłówku może zostać zwrócony nie tylko jeden adres IP</strong>, a kilka oddzielonych przecinkiem, w tym <em>localhost</em>&#8216;y (<a rel="nofollow" href="http://en.wikipedia.org/wiki/X-Forwarded-For">standard nagłówka <code>X-Forwarded-For</code></a>).</li>
<li><strong>Wstrzyknięcie Javascriptów</strong> jest możliwe, ale notabene najmniej szkodliwe, bo do spreparowania nagłówka potrzebny jest bardziej zaawansowany proces (dajmy na to Data Tamping, który przedstawię poniżej), np. niż wklejenie syfu w linku/obrazku i przesłanie go komuś przez komunikator, żeby wykraść jego ciasteczka sesyjne <code>document.cookie</code> i przesłać je sobie na serwer w dowolny sposób, <strong>zatem atakowi nie ulegną osoby trzecie</strong>.</li>
<li><strong>Niepoprawność danych</strong>, które można zmanipulować, jest chyba rzeczą oczywistą: nieprzepuszczenie takich danych przez filtry może skutkować złymi wartościami zwracanymi np. przez <code><a href="http://php.net/ip2long">ip2long()</a></code> i zapis w zupełności nieprzydatnych nam później danych do bazy.</li>
<li>&#8230; <strong>ale największe nieprzyjemności</strong> możemy mieć przez spreparowanie lewych zapytań do baz danych, o ile nie używamy sprawdzonych ORM lub czegokolwiek, co pomaga nam filtrować wartości do niej przekazywane i używane w warunkach zapytań (data binding).</li>
</ol>
<p>Przykład tampingu danych, żeby spreparować niepożądane efekty.</p>
<p>Mamy bardzo prosty, niebezpieczny kod funkcji, która pobiera pierwszy adres na liście adresów oddzielonych przecinkami z <code>$_SERVER['HTTP_X_FORWARDED_FOR']</code> o ile istnieje, natomiast w przeciwnym wypadku <code>$_SERVER['REMOTE_ADDR']</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">&lt;</span> ?php
&nbsp;
<span style="color: #000000; font-weight: bold;">function</span> getUserIp<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
  <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'HTTP_X_FORWARDED_FOR'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #990000;">trim</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">current</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">explode</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">','</span><span style="color: #339933;">,</span> <span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'HTTP_X_FORWARDED_FOR'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #b1b100;">return</span> <span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'REMOTE_ADDR'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000088;">$sUserIP</span> <span style="color: #339933;">=</span> getUserIp<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'Hi &quot;'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$sUserIP</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'&quot;!'</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// first bug while display.</span>
<span style="color: #990000;">var_dump</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">ip2long</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sUserIP</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// second bug while transforming data.</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></div></div>

<p><strong>Pora na przykład manipulacji takich danych.</strong></p>
<ul>
<li>Będziemy używać <a href="https://addons.mozilla.org/en-us/firefox/addon/tamper-data/">Tamper Data</a> dla Firefox&#8217;a.<br />Dość popularny wśród developerów addon do Firefox&#8217;a, pozwala zmodyfikować dane <code>$_POST</code>, <code>$_GET</code>, <code>$_COOKIE</code>, nagłówki, &#8220;w locie żądania&#8221; etc.</li>
<li>Po instalacji w menu <em>Narzędzia</em> pojawi się pozycja <em>Dane Tamper</em>, która uruchamia okienko do podsłuchiwania żądań. Po kliknięciu <em>Rozpocznij</em> podsłuchujemy wszystkie wychodzące żądania z naszej przeglądarki. Każde żądanie nie zostanie przepuszczone, dopóki go nie zmanipulujemy klikając <em>Tamper</em>, lub przepuścimy dalej klikając <em>Wyślij</em>.</li>
<li>Jeżeli zdecydujemy się Tamper&#8217;ować żądanie, naszym oczom ukaże się okno z parametrami. Klikamy prawym przyciskiem myszy na listę parametrów, wybieramy Dodaj i wpisujemy nasz przykładowy, brzydki dla aplikacji nagłówek:<br />
<code>X_FORWARDED_FOR=&lt;script&gt;alert('Test.')&lt;/script&gt;</code></li>
</ul>
<p>Naszym oczom ukazują się co najmniej dwa błędy. Pierwszy to błąd prezentacji danych, który wykorzystuje <code>&lt;script&gt;</code>. O ile nie musimy się tym przejmować, bo naturalnie takie żądania nie są tak łatwo wysyłane, użytkownik nie może paść ofiarą ataku przez kliknięcie w link, który np. ukradnie mu ciasteczka. Dane nagłówkowe nie są w stanie być zmodyfikowane poprzez kliknięcie w link, podobnie jak z danymi <code>$_POST</code> (oczywiście mówimy o przypadkach trywialnych, bez javascript&#8217;owych wymuszanych submitów targetowanych do np. ramek).</p>
<p>Znacznie poważniejszym błędem jest konsekwencja wadliwego formatu danych, które nasza funkcja bagatelizuje. Po pierwsze mamy fałszywe dane zwracane przez <code><a href="http://php.net/ip2long">ip2long()</a></code>, po drugie kto powiedział, że właśnie z tej funkcji korzystamy, a nie zapisujemy danych plain&#8217;em i nie bindujemy pofiltrowanych danych lub instrukcji warunkowych zapytania przez np. sprawdzony ORM.</p>
<p><strong>Rozwiązanie problemu.</strong></p>
<p>Edit: Jak słusznie zauważył Zyx, zapomniałem o tym wspomnieć, że skoro mogą znaleźć się tam dowolne dane przesłane od użytkownika, <strong>nie należy tego pola traktować jako wyznacznik, że jest to numer jego IP</strong>, <u>jest ono bezużyteczne i powoduje potencjalną lukę</u>. Poza zabezpieczeniami to podstawowy argument, żeby o polu zapomnieć i używać <code>$_SERVER['REMOTE_ADDR']</code>.</p>
<p>Po pierwsze funkcja powinna sprawdzać dane wejściowe chociażby <code><a href="http://php.net/preg-match">preg_match()</a></code> lub konwersją do <code><a href="http://php.net/ip2long">ip2long()</a></code> i (jeżeli jest taka potrzeba) spowrotem do <code><a href="http://php.net/long2ip">long2ip()</a></code>. Dwa, pamiętajmy, że w X_FORWARDED_FOR znajdują się śmieci, adresy lokalne sieci,  itd., które należy pominąć przy wyborze adresu z listy po przecinku.</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/atak-xss-server-http-x-forwarded-for/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>MySQL tags</title>
		<link>http://athlan.pl/mysql-tags/</link>
		<comments>http://athlan.pl/mysql-tags/#comments</comments>
		<pubDate>Sun, 09 Jan 2011 23:36:37 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Optymalizacja]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[foregin key]]></category>
		<category><![CDATA[index]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[optymalizacja]]></category>
		<category><![CDATA[tagi]]></category>
		<category><![CDATA[tags]]></category>
		<category><![CDATA[trigger]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=635</guid>
		<description><![CDATA[We wpisie Chmura tagów w PHP, w którym został przedstawiony problem budowy chmury tagów zapisałem przykładowe zapytanie prezentujące przykładowe dane dla klasy, które dosłownie zabija bazę danych zliczając za każdym razem ilość występowań tagów. Dostając feedbacki, zauważyłem, że problem ten jest bagatelizowany przez wiele osób. Spróbujmy zbudować bardziej optymalne rozwiązanie zarządzania strukturą danych w taki sposób, aby [...]]]></description>
			<content:encoded><![CDATA[<p>We wpisie <a href="/chmura-tagow-tagcloud-php/">Chmura tagów w PHP</a>, w którym został przedstawiony problem budowy chmury tagów zapisałem <span style="text-decoration: underline;">przykładowe</span> zapytanie prezentujące <span style="text-decoration: underline;">przykładowe</span> dane dla klasy, które dosłownie zabija bazę danych zliczając za każdym razem ilość występowań tagów. Dostając feedbacki, zauważyłem, że problem ten jest bagatelizowany przez wiele osób. Spróbujmy zbudować <strong>bardziej optymalne rozwiązanie</strong> zarządzania strukturą danych w taki sposób, aby dane wyciągać bardzo bezboleśnie.</p>
<p>Zbudujmy przykładową strukturę bazy danych tagów, do której będziemy przypinać różne rzeczy &#8211; newsy, artykuły, galerie zdjęć, zdjęcia, cokolwiek.</p>
<p>Najprostsza tabela <strong>db_tags</strong> o polach:</p>
<ul>
<li><strong>tag_id</strong>, UNSIGNED, aby zwiększyć zakres INT &#8211; wartości ujemne nie są nam porzebne. Oczywiście primary key oraz auto increment.</li>
<li><strong>tag_name</strong>, chociażby varchar(255)</li>
<li><strong>tag_count</strong>, UNSIGNED, INT, ponownie bez znaku, aby zwiększyć zakres, wartości ujemne są nam niepotrzebne. Tutaj będziemy przechowywać liczbę reprezentującą, ile razy użyto tagu do oznaczenia dowolnego zestawu informacji.</li>
</ul>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> db_tags <span style="color: #66cc66;">&#40;</span>
  tag_id <span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">,</span>
  tag_name <span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">255</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #66cc66;">,</span>
  tag_count <span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span>
<span style="color: #66cc66;">&#41;</span> ENGINE <span style="color: #66cc66;">=</span> INNODB;</pre></div></div>

<p>Zastanówmy się, po czym będziemy sortować tagi. <strong>Warto założyć klucz na pole tag_count</strong>, znacznie przyspieszy późniejsze sortowanie wyników po najpopularniejszych tagach. Jeżeli chcemy sortować po liczbie występowań tagu oraz nazwie (aby chmura była alfabetycznie), warto założyć wspólny klucz na tag_name oraz tag_count. Osobiście sortowanie alfabetyczne zostawiam implementacji klasie tagów dla <a href="http://php.net/ksort">ksort()</a>, bowiem zapytanie wyciągające tagi jest obarczone limitem, zatem wspólny klucz w bazie danych nie jest mi potrzebny &#8211; mniej danych w indeksach.</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">ALTER</span> <span style="color: #993333; font-weight: bold;">TABLE</span> db_tags <span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #993333; font-weight: bold;">INDEX</span> <span style="color: #66cc66;">&#40;</span>tag_count<span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>Tworzymy dowolną strukturę danych, która będzie podpinała się do naszych tagów. Pamiętajmy, że do tagów może podpinać się (a przynajmniej powinno, zależy od założeń początkowych projektu) wiele struktur jednocześnie. Wybrałem najbardziej pospolite &#8211; newsy w tabeli <strong>db_news</strong>.</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> db_news <span style="color: #66cc66;">&#40;</span>
  news_id <span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span><span style="color: #66cc66;">,</span>
  news_title TEXT <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
  news_content TEXT <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span>
<span style="color: #66cc66;">&#41;</span> ENGINE <span style="color: #66cc66;">=</span> INNODB;</pre></div></div>

<p>Pozostało nam stworzyć tabelę wiążącą nasze newsy z tagami (nie tagi z newsami). Tabelę nazwałem <strong>db_news_tags</strong>. Zawierać ona będzie tylko dwa pola przechowujące identyfikator newsa oraz przypisanego do niego tagu, zachowując typ danych wiążących, czyli INT UNSIGNED. Zakładam wspólny primary key dla obu pól.</p>
<ul>
<li><strong>handler_item</strong> &#8211; klucz ID newsa,</li>
<li><strong>handler_node</strong> &#8211; klucz ID tagu.</li>
</ul>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> db_news_tags <span style="color: #66cc66;">&#40;</span>
  handler_item <span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
  handler_node <span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
<span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">&#40;</span>handler_item<span style="color: #66cc66;">,</span> handler_node<span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span> ENGINE <span style="color: #66cc66;">=</span> INNODB;</pre></div></div>

<p>Buduję relacyjną bazę danych. Gdy jakiś tag zostanie usunięty, bądź gdy jakiś news zostanie usunięty, automatycznie powinien zniknąć wpis z tabeli <strong>db_news_tags</strong>, zatem używamy kluczy obcych:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">ALTER</span> <span style="color: #993333; font-weight: bold;">TABLE</span> db_news_tags <span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #993333; font-weight: bold;">FOREIGN</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">&#40;</span>handler_item<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">REFERENCES</span> db_news <span style="color: #66cc66;">&#40;</span>news_id<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #993333; font-weight: bold;">DELETE</span> CASCADE;
<span style="color: #993333; font-weight: bold;">ALTER</span> <span style="color: #993333; font-weight: bold;">TABLE</span> db_news_tags <span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #993333; font-weight: bold;">FOREIGN</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">&#40;</span>handler_node<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">REFERENCES</span> db_tags <span style="color: #66cc66;">&#40;</span>tag_id<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #993333; font-weight: bold;">DELETE</span> CASCADE;</pre></div></div>

<p>Tak zaprojektowaną strukturę danych mogę spokojnie używać do przechowywania danych. Pozostaje kwestia obliczania ilości występowań tagów. Istnieją co najmniej dwie szkoły.</p>
<ol>
<li>Każda zmiana danych w <strong>db_news_handler</strong> wywołuje procedurę liczącą tagi. Trzeba mieć na uwadze, że tagi są przeliczane <strong>od początku</strong> mielenie bazy, ale de facto proces odbywa się po kluczach. Zaletą rozwiązania jest to, że przy bardzo rozbudowanych strukturach (np. liczymy tylko aktywne i widoczne tagi) procedura uwspólnia nam warunki podliczania, używając jej w wielu miejscach nie musimy się martwić o redefiniowanie triggerów.</li>
<li>Dla przedstawionego przykładu w tym poście wystarczy inkrementacja licznika przy dodaniu i dekrementacja przy usunięciu tagu. W większości przypadków właśnie takiego rozwiązania powinno się używać.</li>
</ol>
<p><strong>Luźny komentarz techniczny (problems, tips &#038; tricks):</strong> Aby ominąć problemy wynikłe z założenia w punkcie pierwszym, równie dobrze możemy napisać procedury, które inkrementują/dekrementują liczbę tagów w zależności od warunków (np. tylko wtedy, kiedy tag jest aktywny i widoczny w serwisie). Nikt nie powiedział, że procedury muszą liczyć wszystko od początku możemy się na takie rozwiązanie zgodzić, rezygnujemy natomiast z synchronizacji licznika podczas zmiany warunków, wówczas podczas każdej zmiany warunków, trzeba przekręcić licznik od początku, zliczając wszystkie rekordy wg. ustalonych warunków ręcznie. Triggera należałoby również umieścić w UPDATE (zmiana stanu tagu, np. z niewidocznego na widoczny, z aktywnego na nieaktywny). I to jest najrozsądniejsze rozwiązanie.</p>
<p>W naszym przypadku ograniczymy się do dwóch triggerów, które będą trzymały rękę na pulsie w momencie przypisania tagu do struktury INSERT oraz zerwaniu przypisania DELETE. Zatem:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> NewsTagsCountInsert AFTER <span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">ON</span> db_news_tags
  <span style="color: #993333; font-weight: bold;">FOR</span> EACH <span style="color: #993333; font-weight: bold;">ROW</span> <span style="color: #993333; font-weight: bold;">BEGIN</span>
    <span style="color: #993333; font-weight: bold;">UPDATE</span> db_tags <span style="color: #993333; font-weight: bold;">SET</span> tag_count <span style="color: #66cc66;">=</span> tag_count <span style="color: #66cc66;">+</span> <span style="color: #cc66cc;">1</span> <span style="color: #993333; font-weight: bold;">WHERE</span> tag_id <span style="color: #66cc66;">=</span> <span style="color: #993333; font-weight: bold;">NEW</span><span style="color: #66cc66;">.</span>handler_node;
  <span style="color: #993333; font-weight: bold;">END</span>
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> NewsTagsCountDelete AFTER <span style="color: #993333; font-weight: bold;">DELETE</span> <span style="color: #993333; font-weight: bold;">ON</span> db_news_tags
  <span style="color: #993333; font-weight: bold;">FOR</span> EACH <span style="color: #993333; font-weight: bold;">ROW</span> <span style="color: #993333; font-weight: bold;">BEGIN</span>
    <span style="color: #993333; font-weight: bold;">UPDATE</span> db_tags <span style="color: #993333; font-weight: bold;">SET</span> tag_count <span style="color: #66cc66;">=</span> tag_count <span style="color: #66cc66;">-</span> <span style="color: #cc66cc;">1</span> <span style="color: #993333; font-weight: bold;">WHERE</span> tag_id <span style="color: #66cc66;">=</span> <span style="color: #993333; font-weight: bold;">OLD</span><span style="color: #66cc66;">.</span>handler_node;
  <span style="color: #993333; font-weight: bold;">END</span></pre></div></div>

<p><strong>Komentarz</strong>: bardziej eleganckim w większej strukturze danych byłoby wywołanie procedur inkrementujących i dekrementujących licznik &#8211; wówczas wykonywalibyśmy procedury (nie zapytania) w wielu strukturach wiązanych (nie tylko newsy, a video, ankiety, etc). Zmiana implementacji liczenia tagów byłaby wówczas wiele prostsza &#8211; zmienialibyśmy tylko procedurę, a nie każdy TRIGGER z osobna, zatem:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">PROCEDURE</span> TagsCountIncrement<span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">IN</span> iTagID <span style="color: #993333; font-weight: bold;">INT</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">BEGIN</span>
  <span style="color: #993333; font-weight: bold;">UPDATE</span> db_tags <span style="color: #993333; font-weight: bold;">SET</span> tag_count <span style="color: #66cc66;">=</span> tag_count <span style="color: #66cc66;">+</span> <span style="color: #cc66cc;">1</span> <span style="color: #993333; font-weight: bold;">WHERE</span> tag_id <span style="color: #66cc66;">=</span> iTagID;
<span style="color: #993333; font-weight: bold;">END</span>
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">PROCEDURE</span> TagsCountDecrement<span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">IN</span> iTagID <span style="color: #993333; font-weight: bold;">INT</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">BEGIN</span>
  <span style="color: #993333; font-weight: bold;">UPDATE</span> db_tags <span style="color: #993333; font-weight: bold;">SET</span> tag_count <span style="color: #66cc66;">=</span> tag_count <span style="color: #66cc66;">-</span> <span style="color: #cc66cc;">1</span> <span style="color: #993333; font-weight: bold;">WHERE</span> tag_id <span style="color: #66cc66;">=</span> iTagID;
<span style="color: #993333; font-weight: bold;">END</span>
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> NewsTagsCountInsert AFTER <span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">ON</span> db_news_tags
  <span style="color: #993333; font-weight: bold;">FOR</span> EACH <span style="color: #993333; font-weight: bold;">ROW</span> <span style="color: #993333; font-weight: bold;">BEGIN</span>
    <span style="color: #993333; font-weight: bold;">CALL</span> TagsCountIncrement<span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">NEW</span><span style="color: #66cc66;">.</span>handler_node<span style="color: #66cc66;">&#41;</span>;
  <span style="color: #993333; font-weight: bold;">END</span>
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> NewsTagsCountDelete AFTER <span style="color: #993333; font-weight: bold;">DELETE</span> <span style="color: #993333; font-weight: bold;">ON</span> db_news_tags
  <span style="color: #993333; font-weight: bold;">FOR</span> EACH <span style="color: #993333; font-weight: bold;">ROW</span> <span style="color: #993333; font-weight: bold;">BEGIN</span>
    <span style="color: #993333; font-weight: bold;">CALL</span> TagsCountDecrement<span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">OLD</span><span style="color: #66cc66;">.</span>handler_node<span style="color: #66cc66;">&#41;</span>;
  <span style="color: #993333; font-weight: bold;">END</span></pre></div></div>

<p>Finalnie, z czystym sumieniem:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> tag_name<span style="color: #66cc66;">,</span> tag_count <span style="color: #993333; font-weight: bold;">FROM</span> db_tags <span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> tag_count <span style="color: #993333; font-weight: bold;">LIMIT</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">50</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/mysql-tags/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>[meta]dane dla Facebooka</title>
		<link>http://athlan.pl/metdane-dla-facebooka/</link>
		<comments>http://athlan.pl/metdane-dla-facebooka/#comments</comments>
		<pubDate>Mon, 06 Dec 2010 15:17:18 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Przemyślenia]]></category>
		<category><![CDATA[Usablity]]></category>
		<category><![CDATA[XHTML]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=507</guid>
		<description><![CDATA[Ostatnimi czasy tworząc projekty coraz częściej zwracam uwagę na usability, poprawiając przy tym grafików. Dziś krótko, bo o tym, jak dostosować nagłówki &#60;meta&#62;, aby jak najlepiej były przeklejane do okienka udostępniania linków na Facebook&#8217;u. Czasem cennymi danymi są te, które widzi Google oraz użytkownik (meta description i bezpośrednio w pasku przeglądarki title), czasem zależy nam na dostosowaniu [...]]]></description>
			<content:encoded><![CDATA[<p>Ostatnimi czasy tworząc projekty coraz częściej zwracam uwagę na <em>usability</em>, poprawiając przy tym grafików. Dziś krótko, bo o tym, jak dostosować nagłówki &lt;meta&gt;, aby jak najlepiej były przeklejane do okienka udostępniania linków na Facebook&#8217;u.</p>
<p>Czasem cennymi danymi są te, które widzi Google oraz użytkownik (meta description i bezpośrednio w pasku przeglądarki title), czasem zależy nam na dostosowaniu prezentacji danych agregatorów, w naszym przypadku Facebook&#8217;a, aby użytkownik wklejając linka nie musiał się dodatkowo w nic angażować.</p>
<ol>
<li><strong>Wykryj, czy odwiedza Cię Facebook</strong>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/^facebookexternalhit/'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'HTTP_USER_AGENT'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span></pre></div></div>

</li>
<li>Dostosuj swój <em>meta description</em>. Pamiętaj, że Facebook ucina spore części tekstów, dlatego sprecyzuj najbardziej chwytliwe fragmenty contentu, które mogą przyciągnąć użytkownika. Dodatkowo możesz zmodyfikować <em>title</em> dodając do niego dziwne znaczki (encje), które na pewno przyciągną wzrok.</li>
<li>Przygotuj odpowiedni obraz o odpowiedniej rozdzielczości, a następnie zaserwuj go w tagu:<br />
<code>&lt;link rel="image_src" href=" ... " /&gt;</code><br />
Gdy tego nie zrobisz, użytkownik, który przekleja linka będzie sam musiał zdecydować o obrazie, który zostanie mu zaproponowany z puli dostępnych na stronie. Ta praktyka na szczęście jest często wykorzystywana przez programistów, wydaje się być trywialna.</li>
<li>Jeżeli chcesz wyeksponować ramkę Facebook&#8217;a na swoją stronę www, ustaw transparentność na <em>iframe</em>. Wbuduj ją w diva i nie zapominaj o możliwościach <em>CSS</em> takich jak <em>position</em>: absolute; <em>position</em>: relative; <em>top</em>: -1px; <em>left</em>: -1px; <em>overflow</em>: hidden; aby ukryć czasem kłopotliwe obramowanie <em>iframe&#8217;a</em>.</li>
</ol>
<p>Efekt? Sprawdź sam na <a href="http://www.nowiny365.pl">Nowiny365.pl</a>.</p>
<p style="border: 3px solid red; padding: 10px;">Przeczytaj również o <a href="http://developers.facebook.com/docs/opengraph">OpenGraph</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/metdane-dla-facebooka/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>&#8220;Rekurencja&#8221; w funkcjach/procedurach MySQL</title>
		<link>http://athlan.pl/rekurencja-mysql-funkcje-procedury/</link>
		<comments>http://athlan.pl/rekurencja-mysql-funkcje-procedury/#comments</comments>
		<pubDate>Mon, 22 Nov 2010 12:00:30 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Optymalizacja]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[baza danych]]></category>
		<category><![CDATA[funkcje]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[procedury]]></category>
		<category><![CDATA[publikacje]]></category>
		<category><![CDATA[rekurencja]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=500</guid>
		<description><![CDATA[Odzwyczajony od blogowania, zaabsorbowany przez niekorzystnego dla planet i blogosfery stanu rzeczy Social Media, postanowiłem wrzucić kolejny wpis, w podzięce za porady uzyskane z blogów kolegów z branży. Ostatnio moim zadaniem było zaprojektowanie struktury tabel bazy danych, która wraz z drzewem z zagłębieniem kategorii, ma przechowywać dane na temat cen za ogłoszenia publikowane w tych kategoriach. Założenia [...]]]></description>
			<content:encoded><![CDATA[<p>Odzwyczajony od blogowania, zaabsorbowany przez niekorzystnego dla planet i blogosfery stanu rzeczy Social Media, postanowiłem wrzucić kolejny wpis, w podzięce za porady uzyskane z blogów kolegów z branży. Ostatnio moim zadaniem było zaprojektowanie struktury tabel bazy danych, która wraz z drzewem z zagłębieniem kategorii, ma przechowywać dane na temat cen za ogłoszenia publikowane w tych kategoriach.</p>
<p>Założenia wstępne wyglądały następująco:</p>
<ol>
<li><strong>Każda kategoria może mieć rodzica, ale nie musi.</strong><br />
Jak komu wygodnie, postanowiłem wybrać rozwiązanie z polem <em>category_parent</em> int(11) UNSIGNED, domyślnie NULL (bez rodzica).</li>
<li><strong>Kategorie mogą mieć ustaloną cenę za opublikowanie ogłoszenia, ale nie muszą.</strong><br />
Dodałem pole <em>category_data_price</em> float(6,2) UNSIGNED, domyślnie NULL (niezdefiniowana).</li>
<li><strong>Kategorie</strong>, które nie mają zdefiniowanej ceny, a mają rodzica, <strong>przejmują cenę rodzica w zagłębieniu do nieskończoności</strong>. W przypadku, kiedy cena jest niezdefiniowana również dla rodziców, cena stanowi NULL.</li>
</ol>
<p>Potrzebne mi było zapytanie, które zwróci mi zwyczajnie listę wszystkich kategorii wraz z cenami, uwzględniając zagłębienia, w jakich dana kategoria się znajduje. Podejścia składowania cen są dwa:</p>
<ol>
<li><strong>Można zapisywać</strong> tylko <strong>cenę kategorii</strong>, która jest dla niej zdefiniowana, <strong>a przy wyciąganiu danych rekurencyjnie sprawdzać procedurą/funkcją</strong> cenę rodzica, jeżeli jest niezdefiniowana. I tak w kółko do przypadku, gdy któraś z kategorii będzie już miała zdefiniowaną cenę, bądź nie będzie się już gdzie zagłębić (kategoria nie ma rodzica).</li>
<li><strong>Można zapisać dwie ceny dodając pole dodatkowe</strong>, które przy będzie przechowywało wartość ceny, biorąc ją przy sprawdzaniu cen tylko przy zapisie rekordu do bazy danych.</li>
</ol>
<p>Sposób drugi wydaje się być bardziej rozsądny w przypadku większej ilości zapytań podejmujących dane z bazy. Pierwszy odwrotnie &#8211; częściej wpisujemy coś do bazy. Z początku wybrałem pierwszy sposób, przy założeniu, że ceny będą generowane tylko w panelu administracyjnym, zatem zapytanie nie będzie wykonywane często. Niestety, moje myślenie jest bardziej abstrakcyjne, nastawione na elastyczność rozwiązań, w przyszłości cel istnienia bazy może się zmienić.</p>
<p>Tak czy siak, dla obu rozwiązań, trzeba stworzyć procedurę sprawdzającą ceny po rodzicach. Wygląda mniej więcej tak:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">FUNCTION</span> AnnouncementsCategoriesGetPrice<span style="color: #66cc66;">&#40;</span>iCategoryId <span style="color: #993333; font-weight: bold;">INT</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">11</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">RETURNS</span> <span style="color: #993333; font-weight: bold;">FLOAT</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">6</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">BEGIN</span>
<span style="color: #993333; font-weight: bold;">DECLARE</span> iResult <span style="color: #993333; font-weight: bold;">FLOAT</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">6</span><span style="color: #66cc66;">,</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">DECLARE</span> iPointer <span style="color: #993333; font-weight: bold;">INT</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">11</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">SET</span> iPointer <span style="color: #66cc66;">=</span> iCategoryId;
<span style="color: #993333; font-weight: bold;">SET</span> iResult  <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> category_data_price <span style="color: #993333; font-weight: bold;">FROM</span> cms_announcements_categories <span style="color: #993333; font-weight: bold;">WHERE</span> category_id <span style="color: #66cc66;">=</span> iPointer<span style="color: #66cc66;">&#41;</span>;
&nbsp;
WHILE <span style="color: #66cc66;">&#40;</span>iResult <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">AND</span> iPointer <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span> DO
<span style="color: #993333; font-weight: bold;">SET</span> iResult  <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> category_data_price <span style="color: #993333; font-weight: bold;">FROM</span> cms_announcements_categories <span style="color: #993333; font-weight: bold;">WHERE</span> category_id <span style="color: #66cc66;">=</span> iPointer<span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">SET</span> iPointer <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> category_parent <span style="color: #993333; font-weight: bold;">FROM</span> cms_announcements_categories <span style="color: #993333; font-weight: bold;">WHERE</span> category_id <span style="color: #66cc66;">=</span> iPointer<span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">END</span> WHILE;
&nbsp;
<span style="color: #993333; font-weight: bold;">RETURN</span> iResult;
<span style="color: #993333; font-weight: bold;">END</span></pre></div></div>

<p>Stosować ją można dla SELECT&#8217;u kategorii lub do pozyskania wartości pola tymczasowego przy zapisie do bazy.</p>
<p>Mam nadzieję, że komuś się przyda.</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/rekurencja-mysql-funkcje-procedury/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>jQuery Animate i Easing</title>
		<link>http://athlan.pl/jquery-animate-i-easing/</link>
		<comments>http://athlan.pl/jquery-animate-i-easing/#comments</comments>
		<pubDate>Sat, 08 May 2010 08:17:41 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[JS/Ajax]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[XHTML]]></category>
		<category><![CDATA[interface]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=457</guid>
		<description><![CDATA[Nie można kwestionować faktu, że jQuery.animate() jest jednym z najbardziej potężnych narzędzi jQuery. Służy on do animowania atrybutów CSS (czyli zmiany ich wartości w czasie od obecnego stanu A do definiowanego stanu B). Najprostszą implementacją jQuery Animate jest podanie zbioru atrybutów CSS, które mają ulec zmianie oraz czasu, w jakim ta zmiana ma nastąpić. Nie będę się [...]]]></description>
			<content:encoded><![CDATA[<p>Nie można kwestionować faktu, że <code><a href="http://api.jquery.com/animate/">jQuery.animate()</a></code> jest jednym z najbardziej potężnych narzędzi <strong>jQuery</strong>. Służy on do animowania <strong>atrybutów CSS</strong> (czyli zmiany ich wartości w czasie od obecnego stanu A do definiowanego stanu B). Najprostszą implementacją <strong>jQuery Animate</strong> jest podanie zbioru atrybutów CSS, które mają ulec zmianie oraz czasu, w jakim ta zmiana ma nastąpić. Nie będę się zagłębiał w najprostsze przykłady użycia, <a rel="nofollow" href="http://api.jquery.com/animate/">są one dostępne w oficjalnej dokumentacji</a> jQuery.</p>
<p>Należy pamiętać, że dzięki jQuery jesteśmy w stanie nie tylko płynnie zmieniać kolory, wielkość czcionki, obramowanie, ale także pozycje elementów, nadając stronie dynamicznego kształtu. Domyślnym sposobem animowania (<em>easing</em>) jest płynne przechodzenie. Istnieje natomiast sposób na zmianę adaptera animowania. Robert Penner &#8211; autor pluginu <a rel="nofollow" href="http://gsgd.co.uk/sandbox/jquery/easing/"><strong>jQuery Easing</strong></a> dostarczył nam niewiarygodnie efektowne i proste w implementacji narzędzie. Na oficjalnej stronie pluginu można znaleźć <a rel="nofollow" href="http://gsgd.co.uk/sandbox/jquery/easing/">wiele przykładów animacji</a>, które dostarcza nam dodatek. Efekty widoczne są zwłaszcza przy animowaniu pozycji i wymiarów obiektu, ale następują także w przypadku zmiany koloru &#8211; czyli są aplikowane do zmiany stanu każdego z atrybutów CSS.</p>
<p>Dziś postaram się pokazać efekty, jakie można uzyskać za pomocą <strong>jQuery Animate</strong> rozszerzonego o <strong>jQuery Interface</strong> oraz <strong>Easing</strong>.</p>
<ul>
<li><a href="http://athlan.pl/code/jQueryAnimateEasing/">Przykład różnego rodzaju easingu</a>.</li>
</ul>
<p>Pierwszym krokiem jest wygenerowanie własnej biblioteki <a href="http://jqueryui.com/download">jQuery Interface</a>. Dzięki generatorowi, jesteśmy w stanie ściągnąć tylko te części Interface, które są nam de facto potrzebne, zmniejszając jednocześnie ilość kodu. Klikamy &#8216;deselect all components&#8217;, a w sekcji <em>Effects</em> wybieramy efekty, których będziemy używać. Mnie w tej chwili interesuje <em>Bounce</em> i <em>Slide</em>. W paczce otrzymamy wersję deweloperską (z wcięciami) oraz <em>minified</em>, gotową do publikacji na serwerze.</p>
<p>Do wykorzystania efektu slideowania a&#8217;la iPhone (elastyczne odbicie od krawędzi ściany ekranu) sprowadza się drobny kawałek kodu, w którym istotnym jest parametr <em>easing</em>:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#example'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">animate</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span> left<span style="color: #339933;">:</span> <span style="color: #CC0000;">500</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span> duration<span style="color: #339933;">:</span> <span style="color: #CC0000;">1000</span><span style="color: #339933;">,</span> easing<span style="color: #339933;">:</span> <span style="color: #3366CC;">'easeOutElastic'</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p>Na pewno komuś się przyda.</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/jquery-animate-i-easing/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Chmura tagów Tagcloud w PHP</title>
		<link>http://athlan.pl/chmura-tagow-tagcloud-php/</link>
		<comments>http://athlan.pl/chmura-tagow-tagcloud-php/#comments</comments>
		<pubDate>Sun, 07 Mar 2010 19:12:21 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[tagcloud]]></category>
		<category><![CDATA[tagi]]></category>
		<category><![CDATA[tags]]></category>
		<category><![CDATA[web2.0]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=439</guid>
		<description><![CDATA[Ostatnio byłem zobligowany napisać nową klasę tagów do mojego projektu Sypacz.pl, która de facto zachowała stare API, lecz rozszerzyła swoje funkcjonalności, więc w kodzie projektu nie było wielu zmian. Wena spowodowała to, że zacząłem pisać kod od zera. Cały problem polega na tym, aby napisać na tyle elastyczną klasę tagów, która przyjmie nam zestaw danych, [...]]]></description>
			<content:encoded><![CDATA[<p>Ostatnio byłem zobligowany napisać nową klasę tagów do mojego projektu <a href="http://sypacz.pl">Sypacz.pl</a>, która de facto zachowała stare API, lecz rozszerzyła swoje funkcjonalności, więc w kodzie projektu nie było wielu zmian. Wena spowodowała to, że zacząłem pisać kod od zera.</p>
<p>Cały problem polega na tym, aby napisać na tyle elastyczną klasę tagów, która przyjmie nam zestaw danych, a następnie zaprezentować ją w formie chmury, czym zaopiekuje się arkusz stylów CSS:</p>
<p><code>Nazwa tagu =&gt; Ilość występowań</code></p>
<p>Parę osób mnie pytało, jak wyciągnąć takie informacje z bazy danych:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">SELECT tag_name<span style="color: #339933;">,</span> <span style="color: #990000;">COUNT</span><span style="color: #009900;">&#40;</span>tag_name<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">AS</span> tag_times FROM tags GROUP BY tag_name ORDER BY tag_times LIMIT <span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">50</span></pre></div></div>

<p style="border: 2px solid red; padding: 15px;"><strong><span style="color: #ff0000;">Uwaga!</span></strong> Zaprezentowane wyżej zapytanie jest przykładowe, nieoptymalne, a jedynie służące do testowania chmur tagów na małych, testowych bazach danych. <strong>Optymalna implementacja struktur tagów w bazie danych</strong> dla większych projektów <strong>została opisana we <a href="/mysql-tags/">wpisie MySQL tags</a></strong>.</p>
<p>Wykorzystałem obiekt <a href="http://athlan.pl/code/Attribute.Class">Vframe_Attribute</a>, aby ustandaryzować komponent względem pozostałych w moim frameworku. Jeżeli ktoś nie chce używać obiektu Attribute, może w prosty sposób przekształcić klasę tagów, otrzymując ten sam efekt, deklarując tylko atrybut chroniony <code>protected $_aAttributes = array();</code>. Temat chmury tagów wydaje mi się na tyle trywialny, że nie ma się co nad nim zbyt wiele rozwodzić, zamieszczę tylko klasę i opiszę krótko w przykładach jej możliwości.</p>
<ul>
<li><a href="http://athlan.pl/code/Tagcloud.Class">Vframe_Tagcloud</a> &#8211; klasa tagów,</li>
<li><a href="http://athlan.pl/code/Attribute.Class"> Vframe_Attribute</a> &#8211; pomocnicza klasa atrybutów dla stosu $_aAttributes, dziedziczenie można usunąć i zadeklarować atrybut samemu.</li>
</ul>
<p>Aby stworzyć nowy obiekt tagów, po prostu wywołujemy konstruktor:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$oCloud</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Vframe_Tagcloud<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Konstruktor nie przyjmuje żadnych argumentów, wiec możemy od razu przejść do podawania obiektowi tagów. W tym miejscu warto nadmienić, że każdy znak jest rozróżniany (ze względów elastycznych), więc jeżeli chcesz, aby Nazwatagu oraz nazwatagu były rozpoznawane jako jeden klucz, wypadałoby użyć funkcji <a href="http://php.net/strtolower">strtolower</a> lub <a href="http://php.net/mb_strtolower">mb_strtolower</a> (dla Multibyte Strings):</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$aDataTags</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$iKey</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000088;">$aRow</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000088;">$oCloud</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>add<span style="color: #009900;">&#40;</span><span style="color: #990000;">strtolower</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$aRow</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'tag_name'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$aRow</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'tag_times'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Najistotniejszą częścią klasy jest sposób renderowania chmury, które może działać w dwóch trybach:</p>
<ul>
<li><strong>Tryb prosty</strong> zwraca nam nazwę tagu oraz jego wagę po przeliczeniu w formie liczby.</li>
<li><strong>Tryb zaawansowany</strong> zwraca nam nazwę tagu oraz tablicę z danymi:
<ul>
<li><code>level</code> &#8211; waga tagu po przeliczeniu,</li>
<li><code>count</code> &#8211; ilość występowań, taka jaką podaliśmy,</li>
<li><code>count_percentage</code> &#8211; informacja, w jakiej procentowej części ilości występowań znajduje się tag, przyjmując za 100% tag, który występuje najczęściej.</li>
</ul>
</li>
</ul>
<p>Aby w prosty sposób wyrenderować chmurę tagów, używamy poniższego przykładu:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$aDataTagsRender</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$oCloud</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>render<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Najczęściej używa się trybu prostego. Oba tryby są dalej rozbudowane, bowiem <strong>mamy możliwość zdefiniowania zakresu i dokładności wag tagów</strong>. <span style="text-decoration: underline;">Domyślnie wagi tagów zawierają się pomiędzy 1, a 10</span>. Możemy na przykład przyjąć, że najmniejszą wagą jest liczba 3, największą 5, a precyzja wag tagów to 2 miejsca po przecinku:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$aDataTagsRender</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$oCloud</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>render<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">3</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">5</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>W celu uniknięcia precyzji po przecinku (chcemy otrzymać liczby całkowite), ustawimy precyzję na 0.</p>
<p>Aby wywołać tryb zaawansowany, musimy podać 4 argument dla metody <code>render()</code> i ustawić go na <code>true</code>.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$aDataTagsRender</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$oCloud</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>render<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">5</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Warto w tym miejscu nadmienić, że tagi mogą nie być posortowane alfabetycznie (co ma miejsce podczas tworzenia chmury tagów). Wystarczy wywołać funkcję <code>ksort</code> (key sort).</p>
<p>Finalny przykład używania klasy tagów, celem wywołania klas CSS level_X, gdzie X to liczba całkowita z zakresu od 1 do 10, resztę robi CSS (kolorowanie, nakładanie rozmiaru):</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$aDataTags</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #000088;">$oCloud</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Vframe_Tagcloud<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$aDataTags</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$iKey</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000088;">$aRow</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000088;">$oCloud</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>add<span style="color: #009900;">&#40;</span><span style="color: #990000;">strtolower</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$aRow</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'tag_name'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$aRow</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'tag_times'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$aDataTags</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$oCloud</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>render<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">10</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">ksort</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$aDataTags</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$aDataTags</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$sTag</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000088;">$iTag</span><span style="color: #009900;">&#41;</span>
  <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'&lt;a class=&quot;level_'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$iTag</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'&quot; href=&quot;'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>route<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'tag'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$sTag</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'&quot;&gt;'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$sTag</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'&lt;/a&gt;'</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/chmura-tagow-tagcloud-php/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Recenzja iPhone 3G</title>
		<link>http://athlan.pl/recenzja-iphone-3g/</link>
		<comments>http://athlan.pl/recenzja-iphone-3g/#comments</comments>
		<pubDate>Sun, 17 Jan 2010 10:02:27 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[iTunes]]></category>
		<category><![CDATA[Recenzje]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=413</guid>
		<description><![CDATA[Po trzech miesiącach użytkowania, jestem w stanie napisać konstruktywną recenzję iPhone 3G. Na samym w stępie chciałbym zaznaczyć, że urządzenie jest warte swojej ceny. Moja opinia nie jest w żaden sposób zdeterminowana ślepą miłością do marki Apple. Nie będę się tu rozwodził nad wyglądem, jest to indywidualna sprawa każdego użytkownika telefonu &#8211; dla mnie iPhone [...]]]></description>
			<content:encoded><![CDATA[<p>Po trzech miesiącach użytkowania, jestem w stanie napisać konstruktywną recenzję <strong>iPhone 3G</strong>.</p>
<p>Na samym w stępie chciałbym zaznaczyć, że urządzenie jest warte swojej ceny. Moja opinia nie jest w żaden sposób zdeterminowana ślepą miłością do marki <strong>Apple</strong>. Nie będę się tu rozwodził nad wyglądem, jest to indywidualna sprawa każdego użytkownika telefonu &#8211; dla mnie iPhone ma po prostu elegancki wygląd. Urządzenie wyposażone jest w 4 przyciski: blokowanie telefonu, home button (powrót), wyciszenie i sterowanie poziomem głośności &#8211; klawiaturę zastępuje ekran dotykowy. Warto nadmienić, że pojawia się ona tylko wtedy, gdy jest potrzebna. Telefon ma bardzo czuły ekran z obsługą multi-touch. Wbudowana funkcja auto-jasności pozwala oszczędzać baterię w miejscach ciemnych &#8211; polega to na redukcji oświetlenia ekranu w mroku, gdyż ludzkie oko doskonale widzi, co dzieje się wokół, a rozświetlony (jak za dnia) ekran telefonu powodował by irytację (jak w urządzeniach starszej generacji).</p>
<h4>Zwykłe użytkowanie urządzenia jako telefon</h4>
<p><a href="http://athlan.pl/wp-content/uploads/iphone-springboard.png"><img class="alignright size-full wp-image-428" title="iphone-springboard" src="http://athlan.pl/wp-content/uploads/iphone-springboard.png" alt="" width="250" height="375" /></a>Produkty Apple charakteryzują się dużą intuicyjnością interfejsu. Telefon podzielony jest na dwie zasadnicze części: Text messages (SMS) i telefon. Obie &#8220;aplikacje&#8221; zintegrowane są z komponentem kontaktów, który jest de facto ogólnodostępny dla innych aplikacji (twórcy telefonu podeszli do tej kwestii bardzo ideologicznie). Zasadniczym brakiem w oprogramowaniu jest brak raportów doręczenia SMS, ale można to obejść crackując telefon, o czym później. Dodatkowym minusem jest długie ładowanie się listy SMS przy jej większej ilości, co również można obejść crackując telefon, o czym również później : -). Kolejnym minusem jest to, że wszystkie kontakty przechowywane są w pamięci telefonu, a nie na karcie SIM, co gorsza &#8211; nie ma możliwości eksportu kontaktów na kartę SIM, a jedynie istnieje możliwość importu. Nie ma się czego obawiać &#8211; przy każdej synchronizacji iPhone z iTunes, kontakty zapisywane są w backupie.</p>
<h4>Telefon z niezniszczalnym software</h4>
<p>Zdarzyło mi się &#8220;popsuć&#8221; oprogramowanie iPhone instalując nieautoryzowane przez Apple oprogramowanie na własną odpowiedzialność. Przywrócenie telefonu do stanu używalności? Nic prostszego &#8211; instalujemy nowy software na iPhone via iTunes i klikamy przycisk Restore &#8211; wybieramy nasz backup i gotowe. Wszystkie kontakty, SMS&#8217;y, save&#8217;y z gier, aplikacje, muzyka widnieją z powrotem na ekranie naszego telefonu.</p>
<h4>Urządzenie przyjazne użytkownikowi</h4>
<p>Wyobraź sobie, że słuchasz muzyki, masz telefon w kieszeni, jest zimno. Musisz ściągnąć rękawiczki, wyciągnąć telefon, włączyć odtwarzacz muzyki, wejść  playlistę, kliknąć next, schować telefon, założyć rękawiczki. Nie ma się czym zachwycać, bo rozwiązania te zostały już zaimplementowane z poprzednich telefonach, ale Apple nie zapomniało o przycisku kontrolnym w zestawie słuchawkowym. Pomijając to, że wygląda elegancko, pozwala nam na odebranie/odrzucenie rozmowy i kontrolę iPod&#8217;a (play/pause &#8211; single click, next &#8211; double click, previous &#8211; tripple click).</p>
<p>Wcześniej wspomniałem o ekranie dostosowującym się do warunków oświetlenia. Gdy jest ciemno &#8211; ekran ciemnieje, bo nasze oko akomoduje się do otoczenia, oszczędzamy tym samym baterię. Gdy przykładamy telefon do ucha, ekran wygasza się, aby uniknąć przypadkowych kliknięć w ekran dotykając go uchem &#8211; tutaj również oszczędzamy baterię.</p>
<p><a href="http://athlan.pl/wp-content/uploads/iphone-ipod-cover.png"></a><a href="http://athlan.pl/wp-content/uploads/iphone-sms.png"><img class="alignright" title="iphone-sms" src="http://athlan.pl/wp-content/uploads/iphone-sms.png" alt="" width="250" height="167" /></a>Szybka edycja danych &#8211; na liście wystarczy wykonać gest przeciągnięcia palca w prawą stronę i pojawi nam się przycisk usunięcia go ze stosu &#8211; genialne. Pomyliłeś się pisząc SMS? Potrząśnij telefonem, a iPhone zaproponuje Ci wprowadzenie korekty. Niewygodnie pisze Ci się SMS&#8217;a? Przechyl iPhone na bok, a dostaniesz do dyspozycji większa klawiaturę i większy obszar pola tekstowego. Trzymasz iPhone w ręku i słuchasz muzyki? Potrząśnij telefonem, a zmieni się track. Chcesz przeglądnąć swoje albumy z iPodzie? przechyl telefon, a wyświetlą Ci się okładki, które dodałeś w iTunes.</p>
<p style="text-align: center;"><a href="http://athlan.pl/wp-content/uploads/iphone-ipod-cover.png"><img class="aligncenter" title="iphone-ipod-cover" src="http://athlan.pl/wp-content/uploads/iphone-ipod-cover.png" alt="" width="480" height="320" /></a></p>
<p>Szukanie w całym telefonie &#8211; kolejna opcja, która pomaga mi szybko dostać się do interesujących mnie rzeczy. Jedno pole wyszukiwania odpowiada za wyniki z: aplikacji, kontaktów, maili, sms&#8217;ów, tracków, artystów i albumów z iPod&#8217;a.</p>
<p>Nie ukrywajmy &#8211; Apple dostarcza nam masę aplikacji, z czego wiele jest darmowych. Co więcej, nasz telefon stara się utrzymać całe oprogramowanie w najnowszej wersji. Z telefonu możemy zrobić nawet zwykłą latarkę (której nie ma w urządzeniu) &#8211; aplikacja rozjaśnia ekran i pokrywa go białym kolorem. Nie wspominam już o masie gier serwowanych przez AppStore za darmo!</p>
<div style="text-align: center;"><a href="http://athlan.pl/wp-content/uploads/iphone-appstore.png"><img title="iphone-appstore" src="http://athlan.pl/wp-content/uploads/iphone-appstore.png" alt="" width="250" height="375" /></a> <a href="http://athlan.pl/wp-content/uploads/iphone-games.png"><img class="alignnone size-full wp-image-430" title="iphone-games" src="http://athlan.pl/wp-content/uploads/iphone-games.png" alt="" width="250" height="375" /></a></div>
<p>Przeglądanie Internetu nie było dla mnie prostsze &#8211; wbudowana przeglądarka Safari z obsługą kart i schowka jest idealnym narzędziem do surfowania po Sieci. Player YouTube również spełnia moje oczekiwania. Jeżeli jesteś społecznikiem &#8211; zintegruj swój telefon z Blip&#8217;em, Twitter&#8217;em, Flaker&#8217;em, Facebook&#8217;iem, importuj swoje ulubione kanały RSS, dodaj konta pocztowe i zainstaluj Parlingo &#8211; komunikator z obsługą sieci Gadu-Gadu, Jabbera, ICQ, AOL, Google Talk, MSN i innych.</p>
<h4>Nieautoryzowane oprogramowanie na iPhone &#8211; Jailbreak</h4>
<p><a href="http://athlan.pl/wp-content/uploads/iphone-jailbreak.png"><img class="alignright size-full wp-image-432" title="iphone-jailbreak" src="http://athlan.pl/wp-content/uploads/iphone-jailbreak.png" alt="" width="250" height="375" /></a>Jest wielu zwolenników crackowania oprogramowania iPhone, jest też wielu przeciwników. Moje stanowisko w tej sprawie &#8211; crackować. Co nam to daje? Wcześniej opisałem wiele nieudogodnień, które możemy poprawić w oprogramowaniu, np:</p>
<ul>
<li>raporty SMS są dostępne w Cydii pod nazwą iDelivery,</li>
<li>możemy wyłączyć przycisk automatycznej sekretarki w telefonie, który może nam się zdarzać przypadkowo kliknąć,</li>
<li>mamy możliwość pobierania filmików z YouTube&#8217;a za pomocą MXTube,</li>
<li>możemy scrobblować piosenki przesłuchiwane w iPodzie do last.fm za pomocą Scrobbl,</li>
<li>mamy możliwość zainstalowania kamerki, standardowo niedostępnej w iPhone &#8211; Cycorder,</li>
<li>odblokowanie nowych theme jest teraz możliwe &#8211; Winterboard,</li>
<li>dostosowanie telefonu, wyłączenie EDGE, wyłączanie niepotrzebnych ikonek w Springboard (typu giełda) &#8211; BossPrefs.</li>
</ul>
<p>I na koniec cały smaczek łamania oprogramowania:</p>
<h4>Czyli&#8230; telefon mi &#8216;zamula&#8217;</h4>
<p>Długie ładowanie SMS&#8217;ów, kontaktów, kalkulatora lub alarmów? Zcrackuj swój telefon i zainstaluj Backgrounder z pakietów Cydii. Pozwala on na działanie niektórych aplikacji &#8220;w tle&#8221;. Niektóre możemy ustawić jako automatycznie pracujące w trybie niewidocznym, innym nie pozwolić na taką opcję. Ile razy zdarzyło Ci się przerwać grę, gdy chciałeś odczytać SMS? Przytrzymaj Home button, gra schowa się do paska, odpisz na SMS&#8217;a i ponownie kliknij na ikonkę gry &#8211; powrócisz do stanu pierwotnego, a nie (jak w legalnym oprogramowaniu) proces zostanie całkowicie zakończony. Analogicznie sprawa wygląda w przypadku korzystania z komunikatora (np. Parlingo). Aby wyjść z trybu background, ponownie przytrzymaj Home button. Przycisk wprowadzania aplikacji w stan niewidoczny można skonfigurować indywidualnie, może to być np. Power button (Home jest chyba najwygodniejszy).</p>
<p>Dyskusja na temat działania aplikacji w tle jest burzliwa &#8211; pamiętajmy jednak, że crackując software narażamy się na nieoptymalne działanie telefonu i szybkie zużycie baterii, za co Apple nie odpowiada.</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/recenzja-iphone-3g/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Allegro nie zawsze wygodne</title>
		<link>http://athlan.pl/allegro-nie-zawsze-wygodne/</link>
		<comments>http://athlan.pl/allegro-nie-zawsze-wygodne/#comments</comments>
		<pubDate>Wed, 29 Jul 2009 23:51:57 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[Private]]></category>
		<category><![CDATA[Przemyślenia]]></category>
		<category><![CDATA[allegro]]></category>
		<category><![CDATA[aukcja]]></category>
		<category><![CDATA[aukcje]]></category>
		<category><![CDATA[oszustwo]]></category>
		<category><![CDATA[play station]]></category>
		<category><![CDATA[policja]]></category>
		<category><![CDATA[shopping]]></category>
		<category><![CDATA[zakupy]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=378</guid>
		<description><![CDATA[Jestem zwolennikiem ułatwiania sobie życia wykorzystując Internet do robienia zakupów i zarządzania swoim kapitałem. Natomiast po ostatniej akcji na Allegro, zacząłem wątpić w moje ograne ideały, uznaję to za ostrzeżenie i poprawiam markerem cienką linię pomiędzy realnym shoppingiem, a dokonywania zakupów via Allegro na znacznie grubszą. Zamiast kupić pada do Play Station 3 kiloma kliknięciami, musiałem [...]]]></description>
			<content:encoded><![CDATA[<p>Jestem zwolennikiem ułatwiania sobie życia wykorzystując <strong>Internet</strong> do robienia zakupów i zarządzania swoim kapitałem. Natomiast po ostatniej akcji na <strong>Allegro</strong>, zacząłem wątpić w moje ograne ideały, uznaję to za ostrzeżenie i poprawiam markerem cienką linię pomiędzy realnym shoppingiem, a dokonywania zakupów via Allegro na znacznie grubszą. Zamiast kupić pada do Play Station 3 kiloma kliknięciami, musiałem ruszać tyłek po kilku instytucjach.</p>
<p>Wszystko zaczęło się 25 czerwca, kiedy postanowiłem zakupić wcześniej wspominanego pada. Mam zwyczaj, że jeżeli jest opisana procedura płatności za przedmioty, a kontrahent jest <em>Super Sprzedawcą</em>, robię to od razu po dokonaniu zakupu &#8211; tak było i tym razem. System <a href="http://www.sello.pl/">Sello</a> wysłał mi potwierdzenie złożenia zamówienia.</p>
<p>Od 26.06 do 07.07 obserwowałem status wysyłki. Przelewu nie zaksięgowano po 13 dniach, stąd status wysyłki zakolorowany na czerwono. Sprawa zaczyna śmierdzieć, bowiem nie mogę się dodzwonić do kontrahenta (number busy), a gdy już mi się to udaje &#8211; nikt nie odbiera. Kilkukrotna próba kontaktu telefonicznego i mailowego pozostawiona bez odpowiedzi motywuje mnie, żeby&#8230;</p>
<p>09.07 wypełniłem wniosek w <strong>Centrum Sporów Allegro</strong>. Tego samego dnia wybrałem się na <strong>Policję</strong>, aby złożyć zawiadomienie o popełnieniu przestępstwa na tle wyłudzenia internetowego. Na komendzie czekałem około 40 minut zanim mnie przesłuchali, potem straciłem 30 minut na przesłuchanie i sporządzenie raportu.</p>
<p>Czas płynie i płynie&#8230;</p>
<p>27.07 &#8211; kontrahent dzwoni z wyjaśnieniami. &#8220;Okazało się&#8221;, że odwiedziła go Policja. Tłumaczenie: padła im baza klientów i zamówień, przez co nie mogli mnie zidentyfikować, pomimo szukania transakcji w historii sprzedaży na Allegro (przecież jest lista czarno na białym). Na moim koncie powinny być już zaksięgowane zwrócone pieniążki, ale niestety nie mogą wysłać mi mojego pada ze względu na to, że są zablokowani przez skarbówkę&#8230; muszą się rozliczyć. Za wszystko jeszcze raz przeprasza&#8230;</p>
<p>28.07 godz 11:00, telefon z Policji. Wezwanie na jutro, punkt 9 rano w pokoju numer 53. Sprawdzam konto, pieniążki są. Drukuję potwierdzenie zaksięgowania zwrotu jako załącznik do jutrzejszych zeznań.</p>
<p>29.07 godz 9:00 (wakacje są, daliby pospać). Zaniechujemy ściganie, dziękuję za pomoc. Kończę spór transakcyjny w panelu na Allegro i wystawiam negatywny komentarz:</p>
<blockquote><p>Towar nie dotarł do mnie do dziś. Po interwencji Policji sprawa się wyjaśniła. Natomiast nieuczciwym wobec innych użytkowników Allegro byłoby wystawienie poz. lub neut. komentarza za transakcję, która nie doszła do skutku. Miesiąc w plecy.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/allegro-nie-zawsze-wygodne/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Zintegrowane logowanie cms z forum</title>
		<link>http://athlan.pl/zintegrowane-logowanie-forum/</link>
		<comments>http://athlan.pl/zintegrowane-logowanie-forum/#comments</comments>
		<pubDate>Fri, 06 Feb 2009 09:42:35 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[autoryzacja]]></category>
		<category><![CDATA[cms]]></category>
		<category><![CDATA[forum]]></category>
		<category><![CDATA[logowanie]]></category>
		<category><![CDATA[phpBB]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=214</guid>
		<description><![CDATA[Projektowałem wiele serwisów, które miały zintegrowane z forum komponenty takie jak: rejestracja, przypomnienie hasła, zmiana hasła, nicku lub adresu email, usunięcie konta. Wówczas nie było żadnego problemu &#8211; wystarczyło wszystkie te akcje z forum przekierować na URL&#8217;e obsługiwane przez CMS, który zajmował się zmianami  tabelach forum. Dlaczego przekierować? Jeżeli ktoś rejestruje się w serwisie, jest [...]]]></description>
			<content:encoded><![CDATA[<p>Projektowałem wiele serwisów, które miały zintegrowane z forum komponenty takie jak:</p>
<ul>
<li>rejestracja,</li>
<li>przypomnienie hasła,</li>
<li>zmiana hasła, nicku lub adresu email,</li>
<li>usunięcie konta.</li>
</ul>
<p>Wówczas nie było żadnego problemu &#8211; wystarczyło wszystkie te akcje z forum przekierować na URL&#8217;e obsługiwane przez CMS, który zajmował się zmianami  tabelach forum. Dlaczego przekierować? Jeżeli ktoś rejestruje się w serwisie, jest zarejestrowany na forum, natomiast, gdy rejestruje się na forum, nie jest rejestrowany w serwisie. To CMS integrujemy z forum, a nie forum z CMS&#8217;em (chyba, że zamierzamy inaczej, wtedy na odwrót).</p>
<p>Ostatnio klient zażyczył sobie, żeby zintegrowane było również logowanie. Nie najlepiej widzi mi się implementacja systemu autoryzacji z forum w CMS&#8217;ie, więc poszedłem &#8220;na łatwiznę&#8221;, bowiem miałem do czynienia z <a href="http://przemo.org/phpBB2/">phpBB</a>. Do osiągnięcia celu postanowiłem wykonać dwa kroki:</p>
<ol>
<li>wysłać żądanie POST do forum na adres logowania z wypełnionymi polami POST z formularza logowania w CMS&#8217;ie,</li>
<li>przechwycić wysłane przez forum ciasteczka i przekazać je użytkownikowi.</li>
</ol>
<p>Do połączenia się z forum via http użyłem <a href="http://pl.php.net/HttpRequest">HttpRequest</a>. Wyszło z tego <a href="http://athlan.pl/code/ForumAuth">parę linijek kodu</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/zintegrowane-logowanie-forum/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Logowanie po nickname i email (usability)</title>
		<link>http://athlan.pl/logowanie-nickname-email-usability/</link>
		<comments>http://athlan.pl/logowanie-nickname-email-usability/#comments</comments>
		<pubDate>Sun, 28 Dec 2008 14:35:13 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Przemyślenia]]></category>
		<category><![CDATA[Usablity]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[logowanie]]></category>
		<category><![CDATA[usability]]></category>
		<category><![CDATA[username]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=169</guid>
		<description><![CDATA[Projektując serwisy zaczynam ostrożnie podchodzić do usability. Temat jest bardzo wrażliwy, każdy webmaster to inne zdanie. Dziś chciałbym przedstawić problem logowania do serwisu. Oprócz hasła, przy logowaniu używamy: standardowo nazwy użytkownika, w niektórych serwisach adresu email, rzadziej spotykane zjawisko. W trosce o użytkowników w kilku moich serwisach zastosowałem możliwość logowania się na adres email lub [...]]]></description>
			<content:encoded><![CDATA[<p>Projektując serwisy zaczynam ostrożnie podchodzić do usability. Temat jest bardzo wrażliwy, każdy webmaster to inne zdanie. Dziś chciałbym przedstawić problem logowania do serwisu. Oprócz hasła, przy logowaniu używamy:</p>
<ul>
<li>standardowo <strong>nazwy użytkownika</strong>,</li>
<li>w niektórych serwisach <strong>adresu email</strong>, rzadziej spotykane zjawisko.</li>
</ul>
<p>W trosce o użytkowników w kilku moich serwisach zastosowałem możliwość logowania się na adres email lub nazwę użytkownika. Wszystko po to, aby ułatwić dostęp do ukrytej części witryny, aby nikt nie &#8220;zwątpił&#8221; bo nazwy użytkownika, lub adresu email, który podał przy zakładaniu profilu. Sam używam w sieci kilku adresów email oraz kilku prefixów i suffixów do nicka <strong>Athlan</strong>. Mam problem z zalogowaniem, gdy danie nie pasują, a potrzebuję dostęp tylko na chwilę.</p>
<p>Przygotujmy zatem tok myślenia programu, który pobierze dane, w zależności od tego, jakie dane podał użytkownik. Pomijam walidację hasła etc:</p>
<ol>
<li>Wykrycie, czy nick jest adresem email.</li>
<li>Jeżeli tak, pobierz dane użytkownika po polu <em>user_mail</em> i zapisz je do zmiennej <code>$aUser</code>.</li>
<li>Jeżeli nie, pobierz dane identyfikując rekord po kluczu <em>user_name</em> i zapisz pobrane dane do zmiennej <code>$aUser</code>.</li>
</ol>
<p>Jak możemy zauważyć, w obu przypadkach dane zapisujemy do tej samej zmiennej <code>$aUser</code>, więc możemy je dalej tak samo wykorzystywać. Różni się tylko pobieranie, dlateg nie trzeba w żadnym wypadku powielać kodu.</p>
<ul>
<li><a href="http://athlan.pl/code/UsablityLogin">Przykładowy kod logowania</a>.</li>
</ul>
<p>Jak słusznie zauważył <a href="http://greensky.pl">devnull</a>, <span style="text-decoration: underline;">należy wykluczyć możliwość użycia znaku małpy w loginie przy rejestracji użytkownika</span>. Wyjaśnienie znajdziecie w komentarzach.</p>
<p>Dla programisty nie jest wiele pracy, a warto ułatwić dostęp użytkownikowi do serwisu. <strong>Usability</strong> na pierwszym miejscu ;-)</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/logowanie-nickname-email-usability/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Podtrzymanie sesji</title>
		<link>http://athlan.pl/podtrzymanie-sesji/</link>
		<comments>http://athlan.pl/podtrzymanie-sesji/#comments</comments>
		<pubDate>Fri, 26 Dec 2008 19:35:39 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Przemyślenia]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[Usablity]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[sesje]]></category>
		<category><![CDATA[sessions]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=159</guid>
		<description><![CDATA[Dla niektórych wygasanie sesji jest zabezpieczeniem (banki, etc.). Realizując jeden z projektów oczekiwałem od systemu tego, aby użytkownik nigdy nie gubił sesji, gdy ma otwarte okno w przeglądarce. Dlaczego? Może dodaje posta, być może uzupełnia dość obszerny tekst na stronie. Gdy klika zapisz, przerzuca go do strony logowania, a cały tekst zniknął za sprawą tego, [...]]]></description>
			<content:encoded><![CDATA[<p>Dla niektórych wygasanie sesji jest zabezpieczeniem (banki, etc.). Realizując jeden z projektów oczekiwałem od systemu tego, aby użytkownik nigdy nie gubił sesji, gdy ma otwarte okno w przeglądarce. Dlaczego? Może dodaje posta, być może uzupełnia dość obszerny tekst na stronie. Gdy klika <em>zapisz</em>, przerzuca go do strony logowania, a cały tekst zniknął za sprawą tego, że jego przeglądarka nie zapisuje wartości pól formularza. Skąd to znamy.</p>
<p><strong>Jak użytkownik gubi sesję?</strong></p>
<ol>
<li>Jego ciastko wygasa, więc serwer nie może go zidentyfikować z sesją.</li>
<li>Po jakimś czasie, choćby odtworzył ciastko, plik sesji znika z naszego serwera (<a href="http://pl.php.net/manual/pl/session.configuration.php#ini.session.gc-divisor">garbage collection</a>).</li>
</ol>
<p><strong>Rozwiązania:</strong></p>
<ol>
<li>Wydłużenie czasu wygasania ciastka i sesji.</li>
<li>Odświeżenie strony w interwale mniejszym, niż wynosi czas wygasania sesji i ciastka.</li>
</ol>
<p>Rozmyślając nad podtrzymaniem sesji, próbowałem znaleźć wszystkie metody oraz wybrać najlepszą. Wszystkie sprowadzają się do &#8220;odświeżenia&#8221; strony lub jej fragmentu tak, aby nasz silnik wykonał tylko potrzebne session_start(); czyli podtrzymanie aktywności sesji. Jest kilka mniej lub bardziej zadowalających sposobów:</p>
<ol>
<li><strong>Odświeżenie całej strony.</strong><br />
To może spowodować, że dane wprowadzane przez użytkownika w formularzu zostaną utracone. Ponad to, jeżeli użytkownik czyta newsy, denerwującym może być fakt, że lista nagle zostanie przescrollowana do góry (prócz opery).</li>
<li><strong>Wysłanie requestu ajax w tle.</strong><br />
Minusem jest to, że trzeba używać biblioteki ajax lub pisać dodatkowy kod javascriptu. Jeżeli ktoś na stronie używa jakiegoś ajaxa &#8211; co za różnica. Poza tym same plusy.</li>
<li><strong>Odświeżanie ukrytej ramki</strong> iframe lub elementu frameset.<br />
Minusów usablity prawie brak. Brak potrzeby instalacji javascriptów i ajaxa. Odświeżacz powinien wysłać nagłówek <em>Refresh</em> lub odpowiedni metatag.</li>
</ol>
<p>Sposób 3 wydaje mi się najlepszy. Można go ulepszyć w ten sposób, aby ramka nie wysyłała żądania zaraz po załadowaniu strony. Powodowałoby to podwójne requesty do serwera.</p>
<ul>
<li><a href="http://athlan.pl/code/PingIframe">Przykład z ukrytym iframe</a>.</li>
<li><a href="http://athlan.pl/code/PingAdvajax">Przykład z Advajax</a>.</li>
<li>plik <code>ping.php</code> wygląda wówczas następująco: <span style="color: #999999; font-size: 9px;">aplikacje nie używające frameworków ingerujących w standardowe działanie sesji</span><br />
<code>session_start(); header('Refresh: 60');</code></li>
</ul>
<p><span style="font-size: 9px">Zapewne znajdą się osoby, które powiedzą: a co z użytkownikami, którzy mają wyłączone ramki, lub ich przeglądarki w ogóle ich nie obsługują. Zapytam wówczas: a co z użytkownikami, którzy nie akceptują cisteczek (wówczas sesje nie są dla nich użyteczne, chyba, że użyjemy przesłyki jej identyfikatora w adresie url). Dopytam również: a co z użytkownikami, którzy mają wyłączony Javascript? Patologiczne przepadki się po prostu pomija ;)</span></p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/podtrzymanie-sesji/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Gazeta.pl nie potrafi korzystać z Windowsa?</title>
		<link>http://athlan.pl/gazeta-nie-potrafi-korzystac-z-windowsa/</link>
		<comments>http://athlan.pl/gazeta-nie-potrafi-korzystac-z-windowsa/#comments</comments>
		<pubDate>Sat, 02 Aug 2008 15:47:37 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[Przemyślenia]]></category>
		<category><![CDATA[Recenzje]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Wykop]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=127</guid>
		<description><![CDATA[Podczas przerwy na kawę w godzinach pracy często przeglądam sieć relaksując się czytając newsy. Po kolei włączam onet, interię, tv.wp.pl oraz gazetę. To co ujrzały moje oczy dziś, nie mieści się w głowie: 10 najbardziej wkurzających rzeczy w Windows (serwis sciagnij.pl, subserwis gazeta.pl). Totalna amatorka? Może nietrafny artykuł sponsorowany (dla wymienionego softu)? 1. Dymki z [...]]]></description>
			<content:encoded><![CDATA[<p>Podczas przerwy na kawę w godzinach pracy często przeglądam sieć relaksując się czytając newsy. Po kolei włączam onet, interię, tv.wp.pl oraz gazetę. To co ujrzały moje oczy dziś, nie mieści się w głowie:</p>
<p><a href="http://www.sciagnij.pl/programy/1,90718,5501790,10_najbardziej_wkurzajacych_rzeczy_w_Windows.html">10 najbardziej wkurzających rzeczy w Windows</a> (serwis sciagnij.pl, subserwis gazeta.pl).</p>
<p>Totalna amatorka? Może nietrafny artykuł sponsorowany (dla wymienionego softu)?</p>
<blockquote><p><span class="txt_srodtytul"><strong>1. Dymki z podpowiedziami i ostrzeżeniami</strong></span></p>
<p>Standardowo skonfigurowany Windows co chwilę wyświetla komunikaty o kurczącej się wolnej przestrzeni na dysku czy powiększaniu zapisanego na HDD pliku wymiany. W większości przypadków wyskakujące dymki są zbędne &#8211; informują o rzeczach, o których użytkownik wie albo nie musi wiedzieć.Najprostszym sposobem pozbycia się podpowiedzi jest zainstalowanie bezpłatnego programu XP-AntiSpy (działa także pod Vistą) i zaznaczenie w sekcji &#8220;Inne ustawienia&#8221; opcji &#8220;Nigdy nie pokazuj porad w chmurkach&#8221;.</p>
<p><span style="text-decoration: line-through;">Do pobrania: <a href="http://www.sciagnij.pl/programy/p/XP-AntiSpy/3115">XP-AntiSpy</a></span></p></blockquote>
<p><strong>Komentarz:</strong> Użytkownik powinien być świadomy, że 200 mega miejsca na HDD systemowi może nie wystarczyć. Właśnie na partycji systemowej najczęściej przechowywane są tymczasowe pliki instalacyjne. Szkoda, że MS nie udostępnił narzędzia, w którym można określić ilość krytycznego miejsca na dysku. Ja bym zarezerwował 1.5 giga + miejsce na plików stron.</p>
<blockquote><p><span class="txt_srodtytul"><strong>2. Awanturujące się Centrum Zabezpieczeń</strong></span></p>
<p>W Panelu Sterowania Windows posiada moduł o nazwie Centrum Zabezpieczeń. Ułatwia on zarządzanie zaporą sieciową, antywirusem i automatycznymi aktualizacjami. Kiedy te programy są wyłączone w zasobniku systemowym pojawiają się komunikaty ostrzegające przed zagrożeniami i zachęcające do odwiedzenia Centrum.</p>
<p>Osoby korzystające z samodzielnych zapór <span style="text-decoration: line-through;">(<a href="http://www.sciagnij.pl/programy/p/ZoneAlarm/362">ZoneAlarm</a>, <a href="http://www.sciagnij.pl/programy/p/Ashampoo_Firewall_Free/354">Ashampoo</a>)</span> i chcące w pełni kontrolować instalowanie patchów powinny po otwarciu zakładki Centrum w Panelu Sterowania kliknąć w link &#8220;Zmień sposób informowania mnie&#8230;&#8221; i w kolejnym okienku odznaczyć wszystkie trzy opcje (&#8220;Zapora&#8221;, &#8220;Aktualizacje automatyczne&#8221;, &#8220;Ochrona przed wirusami&#8221;).</p></blockquote>
<p><strong>Komentarz:</strong> Większość programów antywirusowych/zapór informuje system Windows o swojej działalności. Przykład? Avast, Kaspersky. Wówczas chmurki pokazują się tylko wtedy, gdy jest faktyczne zagrożenie komputera (np. gdy wyłączymy zaporę programu antywirusowego lub samą aplikację programu). Użytkownik powinien wiedzieć, że jego system nie jest bezpieczny, jeżeli nie ma zapewnionej ochrony antywirusowej, chmurki są jak najbardziej wskazane, jeżeli je ukrywa, akceptuje to, że sam zatroszczy się o swoje bezpieczeństwo. Potem za szkodliwe działanie wirusa obwiniany jest Windows i Microsoft :)</p>
<blockquote><p><span class="txt_srodtytul"><strong>3. Raportowanie błędów</strong></span></p>
<p>Po &#8220;padzie&#8221; systemu czy aplikacji Windows ma zwyczaj pytania użytkownika o zgodę na przekazanie raportu firmie Microsoft. Większość ludzi podenerwowana klika w tym momencie przycisk &#8220;Nie wysyłaj&#8221;. Problem eliminuje wspomniany już program <a href="http://www.sciagnij.pl/programy/p/XP-AntiSpy/3115">XP-AntiSpy</a>. Wystarczy zaznaczyć opcje &#8220;Wyłącz raporty o błędach&#8221; i &#8220;Office XP: Nie wysyłaj raportu o błędach&#8221; w sekcji &#8220;Raporty o błędach&#8221;.</p></blockquote>
<p><strong>Komentarz:</strong> W zupełności słuszna uwaga, powinna być wbudowana opcja widoczna w ukazującym się oknie o tym, aby zapamiętać wybór.</p>
<blockquote><p><span class="txt_srodtytul"><strong>4. Brak dostępu do skrótów na pulpicie</strong></span></p>
<p>Kiedy użytkownik ma otwarte tuzin okien i potrzebuje dostępu do skrótu na pulpicie musi minimalizować wszystkie foldery oraz programy. Problem ten można rozwiązać włączając pasek szybkiego uruchamiania obok przycisku Start (PKM w pasek Start, polecenie &#8220;Paski narzędzi&#8221; / &#8220;Szybkie uruchamianie&#8221;).</p>
<p>Alternatywą są aplikacje dokletowe. Dzięki nim użytkownicy Windows mogą korzystać z animowanego zestawu skrótów podobnego do tego spotykanego w Mac OS-ie. Takie oprogramowanie obciąża nieco system, ale właściciele nowych maszyn nie powinni zauważyć różnicy. Doklety to estetyczne, w pełni konfigurowalne narzędzie ułatwiające dostęp do programów czy folderów.</p>
<p><span style="text-decoration: line-through;">Pobierz <a href="http://www.sciagnij.pl/programy/p/ObjectDock/3118">ObjectDock</a>, <a href="http://www.sciagnij.pl/programy/p/RocketDock/3121">RocketDock</a></span></p></blockquote>
<p><strong>Komentarz:</strong> Polecam skrót <em>WIN+d</em>.</p>
<blockquote><p><span class="txt_srodtytul"><strong>5. Przyciski chowające się w zasobniku systemowym</strong></span></p>
<p>Aplikacje działające w tle nie są widoczne jako przyciski na pasku Start. Reprezentują je ikony w zasobniku systemowym obok zegara, po prawej stronie ekranu. Niektóre z tych symboli są widoczne, inne chowają się za charakterystyczną strzałką. Problem polega na tym, że prawie zawsze te potrzebne są ukryte.</p>
<p>Większą kontrolę nad ikonami da się uzyskać dzięki opcjom paska Start &#8211; PKM w pasek, polecenie &#8220;Właściwości&#8221;, przycisk &#8220;Dostosuj&#8221; obok pola &#8220;Ukryj ikony nieaktywne&#8221;. Każdemu programowi można przyporządkować jedną z trzech opcji &#8211; &#8220;Zawsze ukryty&#8221; (np. zapora sieciowa), &#8220;Ukryty, gdy nieaktywny&#8221; (np. odtwarzacz MP3) oraz &#8220;Zawsze widoczny&#8221; (np. komunikator internetowy).</p></blockquote>
<p><strong>Komentarz: </strong>Microsoft oddał do dyspozycji perfekcyjne narzędzie &#8211; pasek tray w pełni do zmodyfikowania. Zresztą sam autor neguje swoją wypowiedź w następnym akapicie. Bardzo dobrze, że samemu trzeba wybrać sobie to, co ma być widoczne. Podobne zastosowanie ma miejsce w Firefox 3. Niektóre zakładki są widoczne na pasku zakładek, inne nie. Te bardziej przydatne samemu trzeba sobie &#8220;przeciągnąć&#8221; metodą drag &#8216;n&#8217; drop.</p>
<blockquote><p><span class="txt_srodtytul"><strong>6. Animacje przy minimalizowaniu i maksymalizowaniu okien</strong></span></p>
<p>Kiedy animacje są włączone, minimalizowanie i maksymalizowanie folderów czy programów trwa nieco dłużej. Bajer ten można łatwo wyłączyć zyskując ułamek sekundy &#8211; wszystko dzięki ustawieniom &#8220;Wydajności&#8221; w zakładce &#8220;Zaawansowane&#8221; we właściwościach systemu (można je znaleźć w Panelu Sterowania).</p>
<p>Fanatycy szybkości mogą przejrzeć także pozostałe elementy w oknie &#8220;Opcje wydajności&#8221;. Wyłączenie cieni pod menu czy kursorem, gładkiego przewijania pól list czy wizualnych stylów okien oraz przycisków może pomóc osobom borykającym się z problemem ograniczonych zasobów.</p></blockquote>
<p><strong>Komentarz:</strong> Opcja w pełni do skonfigurowania.</p>
<blockquote><p><span class="txt_srodtytul"><strong>7. Animowany piesek w wyszukiwarce plików</strong></span></p>
<p>Denerwuje i spowalnia użytkownika. Pieska można wyłączyć poprzez polecenie &#8220;Zmień preferencje&#8221; / &#8220;Bez animowanej postaci ekranowej&#8221; (dostępne po wciśnięciu klawisza F3 w dowolnym oknie folderu). Dodatkowo dezaktywuje się tam usługę indeksowania, która w założeniu ma przyspieszać wyszukiwanie plików, a w praktyce często je spowalnia. Użytkowników przywiązanych do starego interfejsu (Windows 95 i 98/98SE) zainteresuje zakładka &#8220;Zmień zachowanie wyszukiwania plików i folderów&#8221;, gdzie można wybrać opcję &#8220;Zaawansowane&#8221;. Dzięki temu &#8220;okienka&#8221; przestaną zadawać głupie pytania typu &#8220;Co chcesz wyszukać?&#8221;. Od razu po wciśnięciu F3 pojawi się pole tekstowe, gdzie wpisuje się słowa kluczowe.</p></blockquote>
<p><strong>Komentarz: </strong>Right-click, wyłącz animowaną postać. Wybór zostanie zapamiętany.</p>
<blockquote><p><span class="txt_srodtytul"><strong>8. Brak możliwości włączania nieautoryzowanych stylów wizualnych</strong></span></p>
<p>Standardowo &#8211; za pośrednictwem właściwości ekranu w Panelu Sterowania &#8211; użytkownik może wybrać jedną z trzech wersji kolorystycznych &#8220;Stylu systemu Windows XP&#8221; lub jedną z kilkunastu klasycznych wariacji. Tymczasem w internecie znajdują się tysiące darmowych layoutów (http://www.themexp.org, http://www.xpthemes.com, http://customize.org/xpthemes).Windows pozwala jednak korzystać tylko ze stylów zatwierdzonych przez Microsoft. To ograniczenie da się obejść, choć wymaga to nieco wysiłku. Kluczowy jest w tym przypadku plik uxtheme.dll zlokalizowany w katalogu C:\Windows\system32. Trzeba go podmienić na &#8220;wolną&#8221; wersję.W razie problemów z aktualizacją (Windows chroni pliki systemowe) można przeprowadzić całą procedurę przy użyciu programów Replacer lub Uxtheme Multi-patcher. Gdyby &#8220;okienka&#8221; chciały przywrócić oryginalną wersję &#8211; wyświetlając specjalny komunikat &#8211; należy wybrać polecenie zachowujące nowy plik.</p>
<p>Pobrane style wizualne trzeba umieścić w katalogu C:\Windows\Resources\Themes. Pojawią się wtedy na rozwijalnej liście wyboru we właściwościach ekranu (zakładka &#8220;Wygląd&#8221;).</p>
<p><span style="text-decoration: line-through;">Pobierz: <a href="http://www.sciagnij.pl/programy/p/Replacer/3124">Replacer</a>, <a href="http://www.sciagnij.pl/programy/p/UXTheme_Multi-Patcher/3127">Uxtheme Multi-patcher</a></span></p></blockquote>
<p><strong>Komentarz:</strong> Zgadzam się, opcja powinna być odblokowana. Polecam <a href="http://athlan.pl/jak-moze-wygladac-windows/">Windows Blinds</a>. Niestety płatne. Dla mniej wymagających: <a href="http://www.sciagnij.pl/programy/p/UXTheme_Multi-Patcher/3127">Uxtheme Multi-patcher</a>.</p>
<blockquote><p><span class="txt_srodtytul"><strong>9. Automatyczne aktualizacje</strong></span></p>
<p>&#8220;Okienka&#8221; potrafią same pobierać z internetu i instalować publikowane przez Microsoft łaty. Procedura aktualizacji rozpoczyna się zwykle w najgorszym możliwym momencie &#8211; na przykład wtedy, gdy jest uruchomione dziesięć innych aplikacji. Spowalnia to system &#8211; może prowadzić nawet do jego zawieszenia.Dodatkowo nie wszystkie łatki są potrzebne. Niektórych programów (chociażby Internet Explorera 7) po prostu nie warto instalować. Dlatego lepiej mieć pełną kontrolę nad aktualizacjami. Samoistne sprawdzanie dostępności łatek wyłącza się w oknie &#8220;Aktualizacje automatyczne&#8221; (Centrum Zabezpieczeń w Panelu Sterowania). Procedurę da się przeprowadzić ręcznie wybierając polecenie &#8220;Windows Update&#8221; z Menu Start.</p></blockquote>
<p><strong>Komentarz: </strong>Zarówno czas, sposób jak i instalowanie poszczególnych łatek można w pełni konfigurować we własnym zakresie. Microsoft daje wolną rękę użytkownikowi.</p>
<blockquote><p><span class="txt_srodtytul"><strong>10. Niedziałające kodeki</strong></span></p>
<p><a href="http://www.sciagnij.pl/programy/p/Windows_Media_Player/1055">Windows Media Player</a> to wielki program z mnóstwem funkcji, który ma problemy podczas odtwarzania nawet najbardziej popularnych formatów plików. Bardzo często aplikacja chce łączyć się z siecią i pobierać dodatkowe kodeki. W większości przypadków taka operacja kończy się znanym bardzo dobrze użytkownikom &#8220;okienek&#8221; niepowodzeniem.Aby nie mieć kłopotów z odtwarzaniem nawet egzotycznych formatów audio i wideo najlepiej zainstalować <a href="http://www.sciagnij.pl/programy/p/K-Lite_Mega_Codec_Pack/148">K-Lite Mega Codec Pack</a>. Zawiera on wszystko, co potrzebne, aby słuchać radia w standardzie Real czy oglądać filmy DivX albo MKV. WMP często nie rozpoznaje alternatywnych kodeków. Wtedy z pomocą przychodzi niewielki Media Player Classic, część pakietu K-Lite.</p>
<p>Pobierz <a href="http://www.sciagnij.pl/programy/p/K-Lite_Mega_Codec_Pack/148">K-Lite Mega Codec Pack</a>.</p></blockquote>
<p><strong>Komentarz:</strong> WMP sam pobierze sobie odpowiednie kodeki, jeżeli nie zainstalujemy Mega Codec Packa. Uzupełnianie zasobów przez WMP to minus? Ooops. Chyba zły punkt numer 10. Chyba żeby była okrągła liczba, nie 9.</p>
<p><strong>Podsumowanie:</strong></p>
<p>System windows nie atakuje, a ostrzega użytkownika. Znaczną większość powiadomień można wyłączyć na swoją odpowiedzialność. Ale potem często pojawiają się opinie: &#8220;jaki ten Windows jest lipny&#8221;. A ostrzegał.</p>
<p>Jeżeli podoba Ci się artykuł, <a href="http://www.wykop.pl/link/82922/gazeta-pl-nie-potrafi-korzystac-z-windowsa">wykop go</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/gazeta-nie-potrafi-korzystac-z-windowsa/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>dev.php.pl</title>
		<link>http://athlan.pl/dev-php-pl/</link>
		<comments>http://athlan.pl/dev-php-pl/#comments</comments>
		<pubDate>Mon, 03 Dec 2007 20:47:07 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[php.pl]]></category>
		<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://athlan.vgroup.pl/devphppl/</guid>
		<description><![CDATA[Dziś opublikowałem specyfikację usługi dev.php.pl. Zainteresowanych zapraszam na forum. Warto podkreślić, że Zarząd PHP.pl nie będzie budował usługi sam, tylko z uzytkownikami dostosowywujac się do ich potrzeb. Po co to wszystko? Forum przegląda masę talentów, które niestety nie mogą się wykazać. Poprzez dołączenie domeny dev otworzymy furtkę tym, którzy nie mieli okazji przedstawić swoich możliwości, a patrząc na niektóre projekty [...]]]></description>
			<content:encoded><![CDATA[<p>Dziś opublikowałem specyfikację usługi <a HREF="http://forum.php.pl/Dev_f104.html">dev.php.pl</a>. Zainteresowanych zapraszam na <a HREF="http://forum.php.pl/Specyfikacja_uslugi_devphppl_t82122.html">forum</a>.</p>
<p>Warto podkreślić, że Zarząd PHP.pl nie będzie budował usługi sam, tylko z uzytkownikami dostosowywujac się do ich potrzeb.</p>
<blockquote><p>Po co to wszystko? Forum przegląda masę talentów, które niestety nie mogą się wykazać. Poprzez dołączenie domeny dev otworzymy furtkę tym, którzy nie mieli okazji przedstawić swoich możliwości, a patrząc na niektóre projekty można dostrzec tylko namiastkę umiejętności programowania i co najważniejsze &#8211; pomysłowości &#8211; naszego community. Dodatkowo wortal php.pl będzie starał się promować najlepsze projekty poprzez wymienienie ich tytułów i innych materiałów na stronie głównej nowopowstałego serwisu.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/dev-php-pl/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Internet 100-krotnie szybszy?</title>
		<link>http://athlan.pl/internet-100-krotnie-szybszy/</link>
		<comments>http://athlan.pl/internet-100-krotnie-szybszy/#comments</comments>
		<pubDate>Tue, 13 Nov 2007 16:22:31 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[Wykop]]></category>

		<guid isPermaLink="false">http://athlan.vgroup.pl/internet-100-krotnie-szybszy/</guid>
		<description><![CDATA[Ostatnio wykopałem w sieci ciekawy artykuł: Australijski naukowiec opracował technologię, która 100-krotnie przyspieszy prędkość przesyłania danych za pośrednictwem Sieci. John Papandriopoulos w swojej pracy doktorskiej opisał algorytm, który pozwoli na zredukowanie interferencji sygnału w łączach DSL. Redukcja interferencji oznaczałaby, że przepustowość takich łączy zwiększyłaby się z obecnych 1-10 Mbps do 100-250 Mbps. To z kolei [...]]]></description>
			<content:encoded><![CDATA[<p>Ostatnio wykopałem w sieci ciekawy artykuł:</p>
<blockquote><p>Australijski naukowiec opracował technologię, która 100-krotnie przyspieszy prędkość przesyłania danych za pośrednictwem Sieci. John Papandriopoulos w swojej pracy doktorskiej opisał algorytm, który pozwoli na zredukowanie interferencji sygnału w łączach DSL. </p>
<p>Redukcja interferencji oznaczałaby, że przepustowość takich łączy zwiększyłaby się z obecnych 1-10 Mbps do 100-250 Mbps. To z kolei może w ciągu kilku najbliższych lat zrewolucjonizować Internet. Pierwsze układy, w których zostanie zastosowany nowy algorytm powinny trafić na rynek w ciągu 2-3 lat.</p>
<p>Problem interferencji pojawia się w momencie, gdy próbujemy wycisnąć większą przepustowość z miedzianych łączy telefonicznych. Interferencje zakłócają przepływ danych i zmniejszają w ten sposób przepustowość łącza &#8211; wyjaśnia Papandriopoulos.</p></blockquote>
<p>Jeżeli to prawda, poczekamy około 5-10 lat na implementacje rozwiązania we wszystkich sieciach.</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/internet-100-krotnie-szybszy/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>WordPress sitemap plugin</title>
		<link>http://athlan.pl/wordpress-sitemap-plugin/</link>
		<comments>http://athlan.pl/wordpress-sitemap-plugin/#comments</comments>
		<pubDate>Tue, 28 Aug 2007 21:28:23 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[Przemyślenia]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[Wordpress]]></category>

		<guid isPermaLink="false">http://athlan.vgroup.pl/wordpress-sitemap-plugin/</guid>
		<description><![CDATA[Na potrzeby pewnego projektu o pewnej nazwie, o której niebawem się przekonacie, powstał nowy plugin. Generuje on sitemapa przyjaznego dla Google. Po co to wszystko&#8230; Rejestrując się w google mamy możliwość skorzystać z wielu narzędzi webmastera. Jednym z nich jest &#8220;pomaganie&#8221; robotowi w indeksowaniu naszej strony, poprzez podanie mu sitemapu po którym powinien się poruszać. [...]]]></description>
			<content:encoded><![CDATA[<p><img SRC="http://vgroup.pl/www/img/projects/project_contexlink_sitemap.jpg" ALIGN="left" BORDER="1" HEIGHT="160" HSPACE="10" VSPACE="10" WIDTH="160" />Na potrzeby pewnego projektu o pewnej nazwie, o której niebawem się przekonacie, powstał nowy plugin. Generuje on sitemapa przyjaznego dla <a HREF="http://google.com">Google</a>. Po co to wszystko&#8230; Rejestrując się w google mamy możliwość skorzystać z <a HREF="https://www.google.com/webmasters/tools/siteoverview">wielu narzędzi webmastera</a>. Jednym z nich jest &#8220;pomaganie&#8221; robotowi w indeksowaniu naszej strony, poprzez podanie mu sitemapu po którym powinien się poruszać. Po <a HREF="http://www.google.com/support/webmasters/bin/topic.py?topic=8472">zweryfikowaniu</a> naszej strony w systemie google, proszeni jesteśmy o podanie sitemapu (<a HREF="http://www.google.com/support/webmasters/bin/topic.py?topic=8472">więcej o weryfikacji</a>).</p>
<p ALIGN="left">W tym miejscu z pomocą przychodzi nam <strong>WordPress ContexlinkSitemap Plugin</strong>. Plugin przede wszystkim:</p>
<ul>
<li>tworzy mapę witryny uwzględniając wszystkie notki i podstrony na blogu oznaczone jako &#8220;published&#8221;,</li>
<li> uwzględnia strukturę permalinków, URL&#8217;i przyjaznych dla wyszukiwarek sprecyzowanych w konfiguracji bloga</li>
<li>datę ostatnich zmian na stronie głównej oraz w każdym linku z osobna</li>
<li>dostosowany do mapy google:<br />
<a HREF="https://www.google.com/webmasters/tools/docs/pl/protocol.html">https://www.google.com/webmasters/tools/docs/pl/protocol.html</a></li>
<li>jest bezpłatny : -)</li>
</ul>
<p ALIGN="left"><strong>Instalacja pluginu:</strong></p>
<ol>
<li><a HREF="http://athlan.vgroup.pl/wp-content/uploads/ContextlinkSitemap.rar">Pobierz paczkę pluginu stąd (format ZIP)</a></li>
<li>Folder <em>ContextlinkSitemap </em>skopiuj do folderu <em>wp-content/plugins/</em></li>
<li>Plik sitemap.xml skopiuj do folderu głównego bloga i nadaj mu chmod 777</li>
<li>Aktywuj plugin w zakładce <em>Plugins</em> wpanelu administracyjnym bloga</li>
</ol>
<p ALIGN="left"><strong>Dodanie mapy witryny do google:</strong></p>
<ol>
<li>Zaloguj się na google.com na swoje Google Account lub Gmail Account.</li>
<li>W nagłówku strony głównej google.com przejdź w sekcję &#8220;Moje konto&#8221;</li>
<li>Z listy &#8220;Moje usługi&#8221; wybierz pozycję &#8220;Narzędzia dla webmasterów&#8221;</li>
<li>Dodaj swoją stronę.</li>
<li>Wybierz formę weryfikacji strony i postępuj ze wskazówkami google</li>
<li>Gdy strona pojawi się w tabeli oraz jej status zostanie oznaczony jako &#8220;zweryfikowana&#8221;, kliknij w opcję &#8220;Dodaj mapę&#8221; i podaj adres URL mapy strony <em>(defaultowo http://twojblog.pl/sitemap.xml, czyli tam, gdzie wrzuciłeś plik)</em>.</li>
</ol>
<p ALIGN="left"><strong>Dodatkowa konfiguracja:</strong></p>
<p ALIGN="left">W celu szczegółowej konfiguracji pluginu, możesz:</p>
<ul>
<li>zmienić ścieżkę mapy w stałej CONTEXLINK_MAP_FILE</li>
<li>zmienić częstotliwość automatycznej aktualizacji mapy w stałej CONTEXLINK_MAP_UPDATE, wartość podawana w sekundach, defaultowo co 2 dni: 3600 * 24 * 2.</li>
<li>zmienić miejsce wykonywania aktualizacji, zwykle jest to przy ładowaniu sekcji head na blogu. Aby dokonać zmian, należy zmienić miejsce akcji: add_action(&#8216;wp_head&#8217;, &#8216;ContexlinkSitemapAutogenerate&#8217;); Pełną listę miejsc, w których można wykonać operację możesz znaleźć tutaj: <a HREF="http://codex.wordpress.org/Plugin_API/Action_Reference">http://codex.wordpress.org/Plugin_API/Action_Reference</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/wordpress-sitemap-plugin/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
<!-- WP Super Cache is installed but broken. The path to wp-cache-phase1.php in wp-content/advanced-cache.php must be fixed! -->
