Napisane przez: wisnia | maj 27, 2009

Matura, wakacje, praca…

Witam po prawie półrocznej przerwie :) !

Dostałem już wolne od szkoły i maturki, która swoją drogą poszła całkiem nieźle, czas na parę nowych wpisów i wieści z frontu ;)

Napisane przez: wisnia | grudzień 3, 2008

HowTo: get X and Y position of DOM element in JavaScript

Basically, there is no obvious way to get x and y coordinates of, for example, input element. Why need this? For example to make autocompleter window show always under the given input.

I’m sure that JavaScript frameworks offer this functionality, but when we need slick script adding framework that is 10 times bigger than our software.

Let’s begin then.

What JavaScript actually offers?

Actually we can get element position – relative to it’s parent node, it is stored in offsetLeft and offsetTop properties.

The absolute position is the sum of all relative position, something like relative to root (in this case the BODY element) node position.

Every DOM element has offsetParent property, that is reference to parent object. When we reach the root node offsetParent is null. Therefore using we can build a loop that will sum all postions for us.

The Code

function getX(obj){

	var x = 0;

	while(obj.offsetParent) {
		x += obj.offsetLeft;
		obj = obj.offsetParent;
	}

	return x;

}

function getY(obj){

	var y = 0;

	while(obj.offsetParent) {
		y += obj.offsetTop;
		obj = obj.offsetParent;
	}

	return y;

}

Usage:

alert( getY(document.getElementById("element")) );

Simple!

In next post we’ll try to build autocompleter, learning something new and using this functions above…

Napisane przez: wisnia | grudzień 2, 2008

Making conditional INSERTs in MySQL 5

What?

My task was to add some data to the tables that I did not designed, and there I can’t add some KEYS for me to determine if some rows has the same values in some fields. I’ve been digging through documentation and this is what I’ve came up with;

How?

In MySQL we can add some data using INSERT + SELECT:

INSERT INTO sexy_table (cell1, cell2, cell3)
SELECT 'valueForCell1', 'valueForCell2', 'valueForCell3'

If there is no fields in select (known as “rows have gone for a beer”) INSERT will not continue to execute and no error will be thrown.

Now, to have empty SELECT (known as don’t insert anything!) we have to add some logical conditions that will give us FALSE value. But

SELECT 'var1' WHERE 1=2

does not work!
But here a little, tiny, sweet keyword gives us a helping hand: the DUAL keyword.
It will act as dummy table, just to have some compilance withl SQL language. So the statement looks like this:

SELECT 'var1' FROM DUAL WHERE FALSE

Result: no rows, note that 1=2 is equal to FALSE keyword.

Now, non working, but proper, SQL INSERT (who the hell need it?!)

INSERT INTO sexy_table (cell1, cell2, cell3)
SELECT 'valueForCell1', 'valueForCell2', 'valueForCell3' FROM DUAL WHERE FALSE

using all of this easy stuff above we can solve our problem: how to chceck if data already exists in DB before inserting.

The Solution

Assuming that cell1 is the cell that has to be unique:

INSERT INTO sexy_table (cell1, cell2, cell3)
SELECT 'valueForCell1', 'valueForCell2', 'valueForCell3' FROM DUAL
WHERE NOT EXISTS( SELECT * FROM sexy_table WHERE cell1 = 'valueForCell1')

Easy huh? :)

Goodbye word

The example above shows that many of operations we can do before inserting, just use your invention to boost up your queries!

Napisane przez: wisnia | wrzesień 11, 2008

Installing Rockbox on Compact Flash enabled IPod Mini

Background

My IPod Mini has broken few months ago, and one day i’ve digged it out and thought that it would be not that stupid to finally get it working by replacing hard disk that caused problems.

After googling a little i’ve figured that Compact Flash card can be a replacement for Microdrives Apple put in IPods Mini.

What CF?

Note that CF you’ll try to install in IPod has to support True ATA access mode – before buying check on producer’s webpage for specifications. I used Transcend 133x 8GB CF card to replace old and broken 6GB Hitachi Microdrive.

Installing mere IPod firmware

The eaisiest way is to connect your CF enabled IPod to Windows machine with ITunes, and use “restore” option.

On Linux you’ll have to dd firmware directly to the firmware partition – the corresponding tutorial how to do this you’ll find on rockbox.org

Installing Rockbox

To get Rockbox, the ubiquitous music player firmware, you’ll need 2 things on your IPod: the bootloader and the Rockbox actual firmware.

Rockbox can be installed in normal way, just by unpacking latest build suitable for your device (can be found on http://build.rockbox.org/), or using RockboxUtility

Bootloader is installed by IPodPatcher console program that can be found on http://www.rockbox.org/twiki/bin/view/Main/IpodPatcher , however the image that it contains doesn’t like CF cards, more precisely it soes not recognize partitions that are made on IPod (first ~30MB partition for firmware, rest for stuff). Happily some people made working bootloaders for us, that can be found on:

http://www.rockbox.org/tracker/task/8901?getfile=16426 IPod Mini 1st gen
http://www.rockbox.org/tracker/task/8901?getfile=16980 IPod Mini 2nd gen

Installation goes as described:

  1. Download ipodpatcher.exe and proper bootloader, save it to one folder
  2. Connect IPod in disk mode
    If you ecounter some problems with getting IPod in disk mode try rebooting it by pressing SELECT+MENU for a  moment and then pressing SELECT+PLAY when apple appears – try several times, it’ll succeed :)
  3. Run cmd.exe, navigate to the folder where you’ve saved ipodpatcher.exe
  4. Run
    >ipodpatcher.exe –add-bootloader bootloader.ipod
  5. You’ll be texted with something
    [INFO] Scanning disk devices...
    [INFO] Ipod found - 2nd Generation Mini ("winpod") - disk device 1
    [INFO] Reading partition table from \\.\PhysicalDrive1
    [INFO] Sector size is 512 bytes
    [INFO] Part    Start Sector    End Sector   Size (MB)   Typ
    [INFO]    0              63         80324        39.2   Empty (0x00)
    [INFO]    1           80325      15662302      7608.4   W95 FAT32 (0x0b)
    [INFO] Ipod model: 2nd Generation Mini ("winpod")
    [INFO] Checksum OK in bootloader.ipod
    [INFO] Reading original firmware...
    [INFO]  Wrote 3452928 bytes to firmware partition
    [INFO] Bootloader bootloader.ipod written to device.

Now unplug your IPod and eventually reboot it using SELECT+MENU, Rockbox should now boot.

Słowem wstępu

W poprzednim poście opisałem czym jest memcache i jak go zainstalować i sprawić żeby PHP mogło się z nim komunikować. W tym poście zajmiemy się tym właściwie czego potrzebujemy: wykorzystaniem memcache do zastosowań praktycznych

Kiedy stosować memcache?

Kiedy się tylko da. Ja wykorzystywałem memcache do:

  1. Zapisywania statystyk które pojawiają się na stronie (np. ilość userów na stronie – przykład poniżej, ilość ogłoszeń w bazie etc.)
  2. Przechowywania danych o userze na stronie (jego dane “profilowe”, często pobierane z bazy, przy niezoptymalizowanych zapytaniach, mogą być przechowywane w pamięci serwera)
  3. Przechowywania listy kategorii na stronie – rzecz nieczęsto zmieniana.

Generalizując memcache nadaje się do przechowywania danych których pobranie z bazy danych/internetu/innych (przecież źródłem danych nie zawsze jest baza!) zajmuje dużo czasu lub są pobierane często podczas odwiedzania strony, i nie są to dane często zmieniające się. Niby oczywistość ale warto o tym wszystkim pamiętać przy decyzji czy memcache czy też nie.

Oczywiście prościej posłużyć się miernikiem czasu który nam zwyczajnie powie co jest szybsze: baza czy memcache; prawie zawsze powie memcache ale trzeba jeszcze brać pod uwagę że zasoby pamięciowe serwera memcached są ograniczone i przechowywanie pełnych wyników wyszukiwania albo całych listingów postów w memcache nie jest zbyt dobrym pomysłem.

Jeżeli chodzi o liczniki – postów, komentarzy etc. – memcache oferuje całkiem wygodne funkcje dekrementacji/inkrementacji o których poniżej.

Dokumentacja

Na http://pl.php.net/memcache znajduje się pełna dokumentacja API memcache w PHP.

Prosty przykład połączenia

To zadziała na domyślnych ustawieniach

<?php

// Polacz z memcache
$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ("Could not connect");

// Czy NIE ma danych w memcache?
if(! $data = $memcache->get('blog_testarray')) {

 // Nie ma danych - zapisujemy nowe do memcache 
 $data = array(
 'time' => time(),
 'string' => 'obtained from memcache or not?'
 );

 $memcache->set('blog_testarray', $data, false, 10);
}

// W tym punkcie mamy obecną zmienną $data
// Albo pobraną z memcache poprzez linijkę
//
// if(! $data = $memcache->get('blog_testarray')) {
//
// Albo zdefiniowaną w linii 11

// Pokaż co dostaliśmy
var_dump($data);

?>

Zauważ, że operacja w linii 8 nie jest porównaniem – to przypisanie do zmiennej $data danych zwróconych przez metodę $memcache->get().
Metoda ta zwróci fałsz jeżeli podanego klucza nie ma w memcache – co odwrócone wykrzyknikiem da nam prawdę; Wtedy całość wyrażenia w ifie jest prawdą.

Opisana powyżej składnia sprawdzania czy dane są w memcache wydała mi się całkiem wygodna i właśnie z niej będziemy w tym poście korzystać. Uogólniając:

<?php

if(! $data = $memcache->get('klucz w memcache - dowolny')) {

 // Definicja danych - pobranie z bazy etc etc + zapisanie do memcache 
 $data = foo(). bar();
 $memcache->set('klucz w memcache - dowolny', $data, false, 10 /* Czas ważności keszu */);

}

?>

Co można przechowywać w memcache?

Dowolną zmienną, którą da się serializować – tablice, stringi etc. Wyjątkiem są zmienne resource – np. link do połączenia z plikiem, handler do pliku zwrócony przez fopen() etc.

Teraz trochę o przechowywaniu obiektów:

  1. Jeżeli obiekt posiada metody __sleep() i __wakeup() to zostaną one wykonane przez memcache
  2. Należy pamiętać o tym żeby __sleep() zwracało tablicę właściwości (pól) obiektu do zapisania w memcache – nie zwrócenie tablicy spowoduje wygenerowanie błędu na poziomie E_NOTICE.

Singleton

Memcache jest idealnym materiałem na singletona.

Tak dla przypomnienia: ordynarnie rzecz ujmując singleton to taki obiekt który jest jeden na cały kod.

Nie ma sensu za każdym razem łączyć się z memcache i o ile chcemy uniknąć zabawy w zmienne globalne lub też w przekazywanie za każdym razem obiektu memcache przez parametr, możemy wykorzystać wzorzec singletona. /* O wzorcach też w sumie możnaby napisać jakiegoś posta, nie? */

Oto całkiem prosty przykład singletona dla Memcache:

<?php

/**
 * Memcache sandwitched in The Singleton bread
 *
 * @author Artek Wiśniewski
 * @license BSD
 */
class nsMemcache extends Memcache {

 /**
  * memcached host
  *
  */
 const HOST = 'localhost';

 /**
  * memcached port
  *
  */
 const PORT = 11211;

 /**
  * Instance will be held here
  *
  * @var nsMemcache
  */
 private static $_instance;

 /**
  * Private constructor
  * only class itself can make instances of itself
  * we are doing this to prevent creating multiple objects of nsMemcache
  *
  */
 private function __construct() { 

 	$this->automatedConnect();

 }

 /**
  * This method will connect memcache to server using const values defined above.
  *
  * @throws Exception when connection failed
  */
 private function automatedConnect() {

 	if(! $this->connect(nsMemcache::HOST, nsMemcache::PORT))
 		throw new Exception('Could not connect to the memcached server');

 }

 /**
  * Return ready and connected nsMemcache object
  *
  * @return nsMemcache
  */
 public static function getInstance() {

 	// is singleton present?
 	if(! isset(nsMemcache::$_instance))
 		nsMemcache::$_instance = new nsMemcache();

 	// return one and the same object constantly
 	return nsMemcache::$_instance;

 }

}

?>

Mam nadzieję że komuś się przyda ;)

A na wzorce (którem znam i stosowałem) zapraszam do następnego posta…

Aaaaa i bym zapomniał, jak tego używać?
Ustawiamy sobie stałe HOST i PORT, klasę includujemy, i potem w dowolnym miejscu kodu:

<?

$mc = nsMemcache::getInstance();
$val = $mc->get('some_funky_key');
// works like normal Memcache class...
// ...

?>
Napisane przez: wisnia | sierpień 25, 2008

memcache – instalacja w Windows, PHP

Słowo wstępu

Jak wszyscy wiemy czasem na stronach podajemy dane które wcale nie muszą być aktualne za każdym razem kiedy je serwujemy – tak jest np. ze statystykami ilości ogłoszeń na marketo.pl. Podobnie może być z licznikami, powiedzmy, ilości komentarzy, które wystarczy odświeżać tylko przy ściśle określonych sytuacjach takich jak dodanie/usunięcie komentarza – w ten sposób nie bombardujemy za każdym razem bazy COUNT()’ami.

Memcache jest biblioteką – dokładniej daemonem z interfejsem sieciowym – umożliwiającym nam przechowywanie praktycznie dowolnej wartości pod podanym kluczem (identyfikatorem typu string) w pamięci serwera. Mając dobry hosting możemy sobie zarezerwować np. całe 2-3GB pamięci tylko dla memcache i w ten sposób zbudować stronę szybką niczym jurna dziewica.

Instalacja pod linuxem

Skoro używasz linuxa to sobie poradzisz z instalacją memcached.

Instalacja pod windowsem

Do celów testowych – nie polecam serwerów na windowsie.
Na początek musimy się zaopatrzyć w daemona memcached; gotowe binaria dla windoze można pobrać z:

http://code.jellycan.com/memcached/

Archiwum wypakowujemy w dowolnym miejscu i teraz mamy 2 opcje do wyboru: memcache jako aplikacja i memcache jako usługa systemu windows;

W wypadku opcji pierwszej jedyne co musimy uczynić to kliknąć dwukrotnie na ikonkę memcached.exe – i już :)

Kiedy chcemy częściej korzystać z memcached do testów naszej strony go wykorzystującej warto go zainstalować jako usługę:

  1. Uruchamiamy memcached.exe z opcjami memcached.exe -d install
  2. Odpalamy mmc.exe / zarządzanie usługami i uruchamiamy usługę memcached Server lub też wykonujemy komendę
    memcached.exe -d start

    lub
    net start “memcached Server”

Przygotowanie PHP do współpracy z memcache

Na tym etapie mamy już działający serwer memcache na adresie 127.0.0.1, porcie 11211.
PHP oferuje rozszerzenie PECL do komunikacji z memcache – php_memcache.dll - jeżeli ta biblioteka znajduje się w katalogu ext twojej instalacji to wystarczy teraz że dodasz (odkomentujesz) w php.ini linijkę

extension=php_memcache.dll

Jeżeli tej biblioteki nie posiadasz to możesz ją pobrać z

http://pecl4win.php.net/ext.php/php_memcache.dll

Teraz restartujemy naszego Apache i dla pewności w phpinfo() możemy sprawdzić czy moduł został załadowany;

Gdyby moduł nie został załadowany można sprawdzić czy nie ma jakiś dodatkowych plików php.ini do wyedytowania (np. w XAMPP jest ich bodajże 6)

Słowo zakończenia

Teraz już można bawić memcache w PHP, szczegóły kodowania, wygodne praktyki i przykładowe zastosowania opiszę w następnym poście.

Napisane przez: wisnia | sierpień 18, 2008

marketo.pl

Z serii “patrzcie co spłodziłem”:

Marketo.pl jest serwisem łączącym agregator ogłoszeń drobnych z różnych serwisów ogłoszeniowych (olx.pl, marketeo.pl, ale.gratka.pl, gumtree.pl, dwukropek.pl, kupsprzedaj.pl) oraz wyszukiwarkę szperającą w tychże ogłoszeniach.

Nad serwisem pracowałem z Nazinem i popełnienie tegoż oprogramowania zajęło nam koło miesiąca, do jego budowy wykorzystaliśmy nasz framework netSource (hell yeah, do takich zastosowań idealny) działający na PHP5 + hardkorowo wykorzystywaną bazę MySQL 5 (niektóre zapytania przerażają). Oprócz tego mamy podpowiadanie fraz szukania (na razie tylko w zaawansowanych) oparte na mootools. Między linijkami kodu przewija się też memcache. Grafikę wykonał gość z zewnątrz.

Agregacje z innych serwisów wykonuję podframework korzystający z bibliotek netSource (dobrze się złożyło że mieliśmy coś podobnego napisanego już wcześniej) i mnóóóóóóóóóóóóóstwo pregów.

Zapraszam do testów i zgłaszania błędów – których się nie dopatrzyłem, a na pewno gdzieś czekają pod powierzchnią gotowe by uderzyć.

Piszę sobie właśnie pobieranie newsów z różnych stron internetowych, wszystko parsuję sobie za pomocą wygodnych pregów wbudowanych w php. O ile wyciaganie prostych wartości z znaczników HTML nie było problemem i można je zrobić za pomocą wyrażenia

<htmltag>([^<]+)</htmltag> (pobieraj wszystko do znaku “<“)

tak problem się pojawił jak przyszła potrzeba wyciągnięcia jakiejś większej struktury htmlowej, zawierającej child tagi i białe spacje. Krzykniecie lazy dot? No nie do końca, trochę mi to problemów sprawiło, stąd ten post ;)

Przykładowo chcemy do otrzymać wszystko co się znajduje w divie od id “postexcerpt”:

<div id="postexcerpt" class="postbox if-js-closed">
<h3>Excerpt</h3>
<label class="hidden" for="excerpt">Excerpt</label><textarea rows="1" cols="40" name="excerpt" tabindex="6" id="excerpt"></textarea>
			Excerpts are optional hand-crafted summaries of your content. You can <a href="http://codex.wordpress.org/Template_Tags/the_excerpt" target="_blank">use them in your template</a></div>

Oczywiście można sobie całość przeparsować i dojść do tego co chcemy poprzez DOM, ale zeżre nam to mnóstwo czasu i mocy którą możemy zmarnować gdzie indziej.

Początkowo próbowałem wyrażenia

/<div id=”postexcerpt” class=”postbox if-js-closed”>(?<text>.*?)<\/div>/

Mój wierny towarzysz, .*? , tutaj sobie nie radził, więc zacząłem szukać po necie, dokumentacjach i wyszło na to że problem się rozwiązał po kombinacjach własnych – mianowicie lazy dot nie przewiduje w sobie białych spacji, należy je dołączyć. Powstaje nam wyrażenie

/<div id=”postexcerpt” class=”postbox if-js-closed”>(?<text>(\s|.)*?)<\/div>/

W postaci gotowego kodu php

<?php $newsContent = '
<div id="postexcerpt" class="postbox if-js-closed">
<h3>Excerpt</h3>
<label class="hidden" for="excerpt">Excerpt</label><textarea rows="1" cols="40" name="excerpt" tabindex="6" id="excerpt"></textarea>
 	Excerpts are optional hand-crafted summaries of your content. You can <a href="http://codex.wordpress.org/Template_Tags/the_excerpt" target="_blank">use them in your template</a></div>
';

preg_match('/
<div id="postexcerpt" class="postbox if-js-closed">(?<text>(\s|.)*?)<\/div>/', $newsContent, $reg);
var_dump($reg);
?>

który da nam

array(4) {
[0]=>
string(424) "<div id="postexcerpt" class="postbox if-js-closed">
<h3>Excerpt</h3>
<p class="inside">
<label class="hidden" for="excerpt">Excerpt</label><textarea rows="1" cols="40" name="excerpt" tabindex="6" id="excerpt"></textarea>
Excerpts are optional hand-crafted summaries of your content. You can <a href="http://codex.wordpress.org/Template_Tags/the_excerpt" target="_blank">use them in your template</a>
</p>
</div>"

["text"]=>
string(367) "
<h3>Excerpt</h3>
<p class="inside">
<label class="hidden" for="excerpt">Excerpt</label><textarea rows="1" cols="40" name="excerpt" tabindex="6" id="excerpt"></textarea>
Excerpts are optional hand-crafted summaries of your content. You can <a href="http://codex.wordpress.org/Template_Tags/the_excerpt" target="_blank">use them in your template</a>
</p>
"

[1]=>
string(367) "
<h3>Excerpt</h3>
<p class="inside">
<label class="hidden" for="excerpt">Excerpt</label><textarea rows="1" cols="40" name="excerpt" tabindex="6" id="excerpt"></textarea>
Excerpts are optional hand-crafted summaries of your content. You can <a href="http://codex.wordpress.org/Template_Tags/the_excerpt" target="_blank">use them in your template</a>
</p>
"
[2]=>
string(1) "
"
}

Minus tego taki że preg nie rozpozna nam struktury drzewiastej i w razie wystąpienia innego diva wewnątrz naszego przeszukiwanego taga to zapytanie się wysypie i nie wyciągnie całego taga. Tutaj dobrym rozwiązaniem mogłoby być explodowanie na poszczególne divy i zliczanie ile jest otwartych i ile zamkniętych, póki co nie miałem z tym do czynienia i nie zanosi się na to ;)

Napisane przez: wisnia | sierpień 18, 2008

Nowy devblog

Witaj na moim nowym devblogu, do którego mam nadzieję wreszcie coś sensownie popiszę ;) Czasem się zdarzy mi rozwiązać nietypowy dla mnie problem, może komuś się przyda trochę wiedzy przedstawionej tutaj.

Tak czy inaczej, zapraszam do czytania :)

Kategorie