PEKAO i wpadka roku

Weekend upłynął mi na błogim lenistwie, tak szybko, że nawet nie zauważyłem. Nie zaglądałem do gazet ani serwisów informacyjnych, bo i po co, przecież jest weekend :) Nawet się nie spodziewałem, tego co spotka mnie w poniedziałek. Zaczynam sobie czytać newsy, a tu co?

Okazuje się, że bank PEKAO udostępnił (tzn. nie zabezpieczył) dane osobowe ok. 1400 osób ubiegających się o praktyki (lub staże). Bynajmniej nie nastąpiło to za zgodą tych osób. Po prostu katalog, w którym znajdowało się 2800 dokumentów (CV i listy motywacyjne) był ogólnie dostępny. Cała sprawa wyszła na jaw, gdy robot Google’a zaindeksował dokumenty i wszystko zaczęło się pojawiać w wynikach wyszukiwania. Gdy spojrzymy na site strony zainwestujwprzyszlosc.pl możemy podejrzeć sporą ich liczbę. Dokumenty nie są już dostępne w oryginale, ale nadal można je obejrzeć korzystając z linku Wersja HTML (tuż przy wynikach wyszukiwania).

Brak wiedzy lub niekompetencja pracowników dała o sobie znać. Mleko się już rozlało i teraz wypadałoby posprzątać. Za sprzątanie jednak wzięto się równie nieprofesjonalnie. Wypowiedź rzecznika mówi sama za siebie:

To pomysłowość internautów - trzeba było przecież specjalnie wstukać określony adres. Można było oczywiście wymyślić bardziej skomplikowany. Ale musi być jakieś miejsce na serwerze, gdzie fizycznie przechowywane są takie dane.

Hę? Że niby zabezpieczanie danych na dyskach polega na wymyślaniu skomplikowanych nazw katalogów??? Mam nadzieję, że to nie są powszechnie stosowane metody ;)

Więcej na ten temat można przeczytać na:

http://glucik.blogspot.com/2008/07/zainwestuj-w.html
http://www.polityka.pl/pekao-sa-wpadka-roku/Lead121,1569,261522,18/
http://antyweb.pl/zaklinanie-rzeczywistosci-czyli-pekao-sa-o-swojej-wpadce/

5 praktycznych wyrażen regularnych w PHP

Za każdym razem gdy przychodzi mi skorzystać z dobrodziejstwa jakim są wyrażenia regularne (które swoją drogą mogłyby się dorobić jakiegoś ogólnie uznawanego standardu), sięgam po gotowe i sprawdzone wzorce. Poniżej umieściłem kilka najczęściej używanych przeze mnie wyrażeń regularnych wraz z przykładowym kodem w PHP.

Adres email
Walidacja adresu email jest często spotykanym przykładem użycia wyrażeń regularnych. Adres email składa się z 3 podstawowych części:

  • nazwy użytkownika - za sprawdzenie tego elementu odpowiada ([0-9a-zA-Z]([-_.\w]*[0-9a-zA-Z_])*
  • symbolu @
  • oraz nazwy domeny - za sprawdzenie tego elementu odpowiada (([0-9a-zA-Z])+([-\w]*[0-9a-zA-Z])*\.)+[a-zA-Z]{2,9})

Całość daje nam razem uproszczony adres email, którego poprawność możemy sprawdzić używając poniższego kodu:

$test_string = "przykladowy@email.tutaj.pl";
if (preg_match('/^([0-9a-zA-Z]([-_.\w]*[0-9a-zA-Z_])*@(([0-9a-zA-Z])+([-\w]*[0-9a-zA-Z])*\.)+[a-zA-Z]{2,9})$/', $test_string))
{
	echo 'OK';
}
else
{
	echo 'Failed';
}

Adres URL
Czyli format adresowania zasobów internetowych najczęściej kojarzony z adresami stron www. Adres ten możemy rozbić na następujące części:

  • rodzaj protokołu - (http|https|file)
  • opcjonalna nazwa użytkownika i hasło - (\w*:\w*@)?
  • nazwa hosta - [-\w.]+
  • opcjonalny numer portu - (:\d+)?
  • ścieżka dostępu - (/([\w/_.]*
  • zapytanie - (\?\S+)?

Poprawność URLa możemy sprawdza następujący kawałek kodu:

$test_string = "http://login:haslo@www.rogozinski.net:80/admin/test.php?action=edit&id=166";
if (preg_match("/^(http|https|file):\/\/(\w*:\w*@)?[-\w.]+(:\d+)?(\/([\w\-\.\/]*(\?\S+)?)?)?$/", $test_string))
{
	echo 'OK';
}
else
{
	echo 'Failed';
}

Adres IP

W wydaniu IPv4, są to cztery liczby od 0 do 255 oddzielone kropkami.

$test_string = "255.255.255.0";
if preg_match('/^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:[.](?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$/', $test_string))
{
	echo 'OK';
}
else
{
	echo 'Failed';
}

Data i godzina (w formacie 24H)

$string = '2007-02-15 03:15';
if (preg_match('/^([0-9]{4}-[0-9]{2}-[0-9]{2})\s((0{0,1}[0-9])|(1[0-9])|([2][0-4])):([0-5][0-9])$/', $string))
{
	echo 'OK';
}
else
{
	echo 'Failed';
}

Kod pocztowy

$test_string = '05-324';
if (preg_match('/^[0-9]{2}[-]([0-9]{3})?$/', $test_string))
{
	echo 'OK';
}
else
{
	echo 'Failed';
}

Wszystkie przykłady wyświetlają napis ‘OK’ w razie prawidłowego rozpoznania wzorca i ‘Failed’ w razie porażki.

Warto zobaczyć:

Even Dummies Wear Seatbelts

Bardzo ciekawa reklama propagująca zapinanie pasów bezpieczeństwa, wyprodukowany przez Fińskie Ministerstwo Transportu.

Odległość Levenshteina przy porównywaniu ciągów znaków

Zwykłe porównywanie stringów czy to w php czy asp, sprowadza się do porównywania napisów znak po znaku i wyniku w postaci true lub false. Czasami jednak potrzebujemy porównać napisy powołując się nie na ich bezpośrednią równość, ale na ich podobieństwo.

Jednym z prostszych algorytmów, który pozwoli nam na zbadanie podobieństwa dwóch ciągów znaków jest algorytm Levenshteina, określający tzw. odległość Levenshteina.

Algorytm w oparciu o zdefiniowane wcześniej operacje proste (np. wstawienie znaku, usunięcie znaku, zmiana znaku na inny) określa najmniejszą liczbę operacji, potrzebnych do transformacji pierwszego napisu w drugi. Łatwo sobie wyobrazić, że dla identycznych napisów odległość Levenshteina będzie równa 0, natomiast dla dwóch całkowicie różnych napisów, będzie równa liczbie znaków dłuższego z ciągów. Krótko mówiąc im mniejsza odległość, tym napisy są bardziej do siebie podobne.

Algorytm ten można modyfikować dodając np. nowe operacje, lub przypisując operacjom wagi.

Warto zauważyć, że PHP dostarcza nam własną implementację algorytmu Levenshteina, możemy jej użyć wywołując funkcję levenshtein.

int levenshtein ( string $str1, string $str2 [, int $cost_ins, int $cost_rep, int $cost_del] )

Natomiast w C# porównywaniem string’ów musimy się zająć sami. Przykładowa implementacja może wyglądać na przykład tak:

public static int LevenshteinDistance(String s1, String s2)
{
	const int cost_ins = 1;
	const int cost_del = 1;
	const int cost_sub = 1;
 
	int n1 = s1.Length;
	int n2 = s2.Length;
 
	int[] p = new int[n2+1];
	int[] q = new int[n2+1];
	int[] r;
 
	p[0] = 0;
	for( int j = 1; j <= n2; ++j )
	{
		p[j] = p[j-1] + cost_ins;
	}
 
	for( int i = 1; i <= n1; ++i )
	{
		q[0] = p[0] + cost_del;
		for( int j = 1; j <= n2; ++j )
		{
			int d_del = p[j] + cost_del;
			int d_ins = q[j - 1] + cost_ins;
			int d_sub = p[j - 1] + (s1[i - 1] == s2[j - 1] ? 0 : cost_sub);
			q[j] = Math.Min( Math.Min( d_del, d_ins ), d_sub );
		}
		r = p;
		p = q;
		q = r;
	}
	return p[n2];
}

Wynikiem funkcji Levenshteina jest liczba całkowita. Co jednak zrobić gdy na podstawie porównania ciągów znaków chcemy je klasyfikować? Liczba całkowita nie jest w tym wypadku zbyt wymowna. Lepszym pomysłem jest uzależnienie wyniku od maksymalnej długości ciągu.

Przykład:

public static float LevenshteinTextComparison(String s1, String s2)
{
	if (s1.Equals(String.Empty) && s2.Equals(String.Empty))
	{
		return 1;
	}
	return 1 - ((float)LevenshteinDistance(s1, s2) / (float)Math.Max(s1.Length, s2.Length));
}

Teraz zamiast mało mówiącej liczby całkowitej, otrzymujemy liczbę rzeczywistą z zakresu <0, 1> określającą podobieństwo napisów. Im bliżej jedynki tym ciągi są bardziej podobne i w drugą stronę, im bliżej zera, tym ciągi bardziej się od siebie różnią.

Przydatne linki:

http://pl.wikipedia.org/wiki/Odległość_Levenshteina
http://en.wikibooks.org/wiki/Algorithm_implementation/Strings/Levenshtein_distance

Zdjęcia w Blogger Play

Matt Cutts na swoim blogu zwrócił uwagę na uzależniające działanie ;) Blogger Play. Szczerze mówiąc jest to moje pierwsze spotkanie z tym bardzo prostym i zarazem wciągającym serwisem.

Blogger Play to slideshow wyświetlający zdjęcia, które są aktualnie wrzucane do systemu Blogger przez ludzi na całym świecie.

Blogger Play

Warto zauważyć, że Flickr również posiada podobną funkcjonalność.

Kontrolki kompozytowe w ASP.NET a ClientID

Wyprodukowałem sobie dzisiaj bardzo prostą kontrolkę kompozytową. Jej zadaniem jest pokazywanie i chowanie div’a z tekstem. Całość odbywa się tylko po stronie klienta. Normalnie (mam na myśli HTML) byłoby to banalnie proste, niestety nie w ASP.

Div’a zastąpił mi Panel, a przycisk po wciśnięciu którego pojawia się panel, powstał jako oddzielna kontrolka (także kompozytowa). Wszystko ładnie złożyłem i opakowałem w metodę CreateChildControls(). Ku mojemu zdziwieniu JavaScript wywoływany po wciśnięciu przycisku powodował błąd. Okazuje się, że ClientId panelu jest puste (względnie nie zawiera wartości, której się spodziewam). Dlaczego? Otóż ClientId nie jest dostępne z poziomu metody CreateChildControls(), prawidłową wartość możemy uzyskać dopiero tuż przed wyrenderowaniem kontrolki, czyli np. na preRenderze.

protected override void OnPreRender(EventArgs e)
{
	// tutaj możemy się odwołać do ClientId kontrolek
}

Faktem jest, że unikalne ID tagów html’owych generowanych przez ASP może być zbudowane tylko przy kompletnym drzewie kontrolek, ale czy nie można było zaoszczędzić czasu i napisać o tym w dokumentacji właściwości ClientId?

Koniec urlopu… wracamy do pracy :|

Jestem świeżo po urlopie. Góry, śnieg i narty. Bez laptopa i internetu (no prawie ;) ). Przede wszystkim bez codziennego pośpiechu. Chwila oddechu, która pozwoliła na oderwanie się od problemów, natłoku myśli i informacji. Mała szansa na zerwanie z codzienną rutyną i szarymi ulicami miasta.

Stok narciarski

Wracam, próbuję nadrobić zaległości, zaczynam czytać i na co trafiam?

- Wiesz, oprócz komputerów jest jeszcze rzeczywistość: kwiaty, drzewa, żywi ludzie…
- To znaczy gdzie, za firewallem?…

Rozbroiło mnie to totalnie :D

Reset iPoda nano

Raz na jakiś czas urządzenia po prostu odmawiają posłuszeństwa i przestają działać tak, jak tego od nich oczekujemy. To samo przydarzyło się mojemu iPodowi. Tuż po tym jak próbowałem podłączyć dwa różne iPody do jednego komputera, jeden z nich (iPod nano) zawiesił się. Co należy zrobić w takiej sytuacji?iPod nano

Czasami po prostu musimy go zresetować, mniej więcej tak, jak to się robi z komputerami. Restart iPoda jest bardzo łatwą czynnością, należy zaznaczyć, że nie spowoduje utraty muzyki, plików ani ustawień.

  1. Sprawdź czy iPod jest odblokowany, przycisk na spodzie odtwarzacza powinien być przesunięty w lewo, tak by nie było widać pomarańczowego tła.
  2. Naciśnij jednocześnie i przytrzymaj przez 10 sekund przyciski “Menu” i “Select” (to ten po środku kółka).

Po zresetowaniu, na wyświetlaczu pojawi się logo Apple, a zaraz potem menu główne. :)

Wpis jest luźnym tłumaczeniem artykułu: http://www.methodshop.net/mp3/ipodsupport/restart/index.shtml

Jestem niewidoczny w Gmail Chat

Google wprowadziło w Gmail Chat nowy status: niewidoczny. Teraz możemy się zalogować i przeglądać listę kontaktów, tak aby inni nie wiedzieli, że jesteśmy dostępni. Opcja ta nie jest jeszcze widoczna w polskiej wersji językowej (można ją zobaczyć po zmianie języka na English (US)), nie ma jej również w kliencie Google Talk.

Gmail Chat

Należy zwrócić uwagę, że status ‘niewidoczny’ występuje tylko w nowej wersji Gmaila.

John Cleese chce kredyt gotówkowy

Pojawiła się pierwsza, z serii reklam banku BZ WBK z Johnem Cleesem, legendarnym liderem kabaretu Monty Python. Wszyscy, którzy lubią absurdalny, brytyjski humor na pewno nieźle się uśmieją :).