RssReader beta 0.2

by 7uk3r0n1n, June 21st, 2008 | No Comments

Projektu ciąg dalszy…

  • Dodałem obsługę (i rozróżnienie) kanałów RSS i Atom.
  • Dodałem możliwość linkowania rzeczy z YouTube
  • Dodałem możliwość usuwania ikon z pulpitu :)

Dziwny bug po drodze… kiedy otwieram nowe “okno” powiedzmy z RSS-em to Filmik z YouTube się resetuje.. będzie trzeba się nad tym zastanowić :)

RssReader beta 0.1

by 7uk3r0n1n, June 19th, 2008 | No Comments

Jak to mówią lepiej późno niż wcale… Kiedyś trzeba skończyć projekt na Aplikacje Internetowe. Temat: “Czytnik RSS z interfejsem Drag & Drop”. Wersja pierwsza z podstawową funkcjonalnością i masą błędów jest już dostępna.

RssReader

Wystarczy kliknąć w powyższy link, zarejestrować się (zarejestruj się jest pod polami formularza logowania) i można już dodawać i czytać kanały. Na razie tylko RSS i nawet nie sprawdza czy jest poprawny ;). Jedno co sprawdza to jak nie będzie tam pliku xml poprawnego… wtedy nici z wyświetlania.

Planuje dodać:

  • Obsługę innych rzeczy (ATOM Feedy, Filmiki z YouTube, inne rzeczy w XML-u ;) )
  • System Ratingu Contentu (jaka nazwa :P)
  • Możliwość tworzenia własnych kanałów z odczytanej treści plus pisania własnej
  • Jakieś społecznościowe bzdety
  • Podizał Contentu na grupy i kategorie

Oczywiście nie wszystko na projekt ;)… zobaczymy, może coś z tego będzie i może coś jeszcze wymyśle.

Silverlight Tutorial cz.I - Hello World

by 7uk3r0n1n, June 16th, 2008 | No Comments

Silverlight logo

Silverlight - nowa technologia Microsoftu mająca konkurować z Flashem. Przenosi wiele funkicji i możliwości WPF i .NET w świat webowy. Wbrew plotkom jednym z głównych założeń jest przenośność i możliwość uruchamiania niezależnie od platformy… więc nie ma się co martwić :). Po więcej informacji zapraszam na http://www.microsoft.com/silverlight/

Przy pierwszym kontakcie pomyślałem.. hmm… ciekawe to może być i rzeczywiście jest to technologia bardziej sprzyjająca programiście. Oddziela w dużej mierze logikę aplikacji od wyglądu. Mi osobiście łatwiej jest napisać aplikację w XAML i C# niż uczyć się ActionScripta i nabywać zdolności plastycznych ;) .

Zacznijmy. Potrzebne są dwie rzeczy Microsoft Visual Studio 2008 oraz narzędzia do obsługi silverlighta do pobrania ze strony Microsoftu.
Silverlight Tools 2 beta 2

Następnie po instalacji uruchamiamy VS2008, tworzymy nowy projekt i z zakładki C# wybieramy Silverlight Application. Pojawi się wybór pomiędzy hostowaniem strony na serwerze VS bądź tworzeniem strony HTML zawierającej naszą aplikację. W tym przydatku nie ma znaczenia, którą opcję wybierzemy.

Po utworzeniu nowego projektu ukazuje się widok pliku XAML naszej aplikacji:

<UserControl x:class=“SilverlightApplication4.Page”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Width=”400″ Height=”300″>
<Grid x:name=”LayoutRoot” background=”White”>
</Grid>
</UserControl>

Zacznijmy od dodania przycisku do tej aplikacji. Wstawiamy go jako dziecko (czyli pomiędzy ;) ) “<Grid>”. Określimy parametry Width(szerokość) i Height(wysokość):

<Button Width=”100″ Height=”50″>
</Button>

Na środku aplikacji pojawi się przycisk… no ale jakiś taki pusty jest :)… to dodajemy do przycisku jakiś tekst:

<Button Width=”100″ Height=”50″>
<TextBlock VerticalAlignment=”Center” Text=”Kliknij Mnie!” TextAlignment=”Center”></TextBlock>
</Button>

Kontrolką odpowiedzialną za tekst jest TextBlock, od razu ustawiamy parametry takie jak:

  • VerticalAlignment - odpowiada za usytuowanie elementu na osi pionowej, ustawiamy na “Center” żeby nasz napis był na środku a nie z góry.
  • Text - chyba jasne ;)
  • TextAlignment - odpowiada za usytuowanie tekstu wewnątrz kontrolki. Ustawiamy na center bo chcemy mieć napis na środku :)

Takim oto sposobem mamy ładny przycisk do kliknięcia. No tak, ale jak klikniemy to co się stanie? no nic właśnie. Trzeba temu zaradzić jakoś. Musimy dodać do przycisku jakiś EventHandler a do tego potrzebna jest nazwa więc modyfikujemy trochę definicje przycisku. Dodajemy atrybut x:Name, który odpowiada za nazwę pod którą obiekt będzie widoczny w C#… taki trochę HTML-owy id (nie może być kilku takich samych w aplikacji). Gdy mamy już nazwę należy dodać atrybut który określa EventHandlera dla konkretnego zdarzenia. Chcemy, żeby kontrolka reagowała na kliknięcie więc dodajemy atrybut Click i przypisujemy mu nazwę EventHandlera. Po modyfikacjach nasz przycisk wygląda tak:

<Button Width=”100″ Height=”50″ x:Name=”Cisk” Click=”Cisk_Click”>
<TextBlock VerticalAlignment=”Center” Text=”Kliknij Mnie!” TextAlignment=”Center”></TextBlock>
</Button>

Klikamy prawym klawiszem myszki na nazwie EventHandlera i przechodzimy do edycji kodu C# (View Code). Powiedzmy, że po kliknięciu wyświetlimy znane i lubiane “Hello World”. w tym celu musimy dodać na początku pliku Page.xaml.cs using System.Windows.Browser; aby mieć dostęp do “przeglądarki”. Potem wywołujemy alert. Taki oto kod wystarczy:


private void Cisk_Click(object sender, RoutedEventArgs e)
{
HtmlPage.Window.Alert(“Hell-o World!”);
}

Wciskamy F5 i możemy się cieszyć naszą pierwszą aplikacją w Silverlight.

Get Microsoft Silverlight

Szybkie pobieranie losowych danych z dużej bazy MySQL

by 7uk3r0n1n, February 28th, 2008 | 8 Comments

Napotkałem dzisiaj ciekawy problem. Musiałem napisać skrypt, który będzie pobierał losową zadaną ilość danych z bazy MySQL. Najprostszą metodą jest zastosowanie zapytania w stylu

SELECT [$kolumny] FROM [$tablica] ORDER BY RAND() LIMIT [$ilosc_elementow]

Takie rozwiązanie jest idealne jeżeli mamy do czynienia z małą tablicą. Problemy pojawiają się jednak, gdy w grę wchodzi sporo elementów. Przy tablicy wielkości 1 250 000 rekordów takie zapytanie zajmie sporo czasu (rzędu minut) jeżeli serwer w ogóle je dopuści ze względu na działanie ORDER BY. Rozwiązanie to wymaga, aby serwer utworzył tymczasową kopie tablicy (dużo miejsca i czasu) oraz posortował ją (dużo czasu) i dopiero wyświetli wyniki. Daje nam to 2*dużo czasu + dużo miejsca… słowa dużo nie lubimy ;) (chyba, że odnosi się do wypłaty).

Kolejnym rozwiązaniem na jakie się natknąłem przeszukując otchłanie google było wylosowanie “offsetu” i pobranie danych za pomocą LIMIT (oraz różne wariacje tego rozwiązania). Moja wersja po paru przeróbkach wyglądała tak :


$query = "select count(*) from [$tabela]";
$result = mysql_query($query);
$max = mysql_fetch_array($result);
$max = $max[0];

for ($i=0; $i<[$ilość_elementów]; $i++)
{
$offset = mt_rand(0,$max);
$query = “select [$kolumny] from [$tabela] limit “.$offset.”,1″;
mysql_query($query);
Wariacje w postaci np:


$sql= mysql_query("SELECT floor(rand()*count(*)) FROM [$tabela]");
$row= mysql_fetch_array($sql);

$offset= $row[0];

$sql= mysql_query(”SELECT * FROM [$tabela] limit $offset,1″);
Pierwszy przykład (ta “moja wersja”) Pobiera pewną ilość rekordów. Pierwszy, zauważalny minus to to, że wylosowane rekordy mogą się powtarzać. Drugim jest czas ;). Przy pobieraniu 10000 rekordów z tabeli 1 250 000 czas był za długi dla standardowych ustawień PHP (>30s). Pomocne okazało się pobieranie danych w paczkach 50 elementowych. Dało to czas równy ok. 27s. Trochę dużo jeżeli chcemy coś jeszcze robić :). Samo zapytanie o zliczenie elementów zajmuje ok 4s (wyobraźmy więc sobie jak wygląda rozwiązanie korzystające z RAND() sql-owego :). Każda pobrana paczka danych 5s.). Reszta czasu to pobieranie danych. Z wyczytanych informacji wynika, że spowodowane jest to LIMIT-em i sposobem jego działania.

Na dobre rozwiązanie natrafiłem w artykule na tej stronie Już przerobiona wersja:


$sql= mysql_query("SELECT count(id) FROM [$tabela]"); //pobieramy ilość elementów w tabeli
$row= mysql_fetch_array($sql);
$max= $row[0];
$temp = array();
for ($i=0; $i<[$ilosc_elementów]/[$rozmiar_paczki]; $i++) //ile razy wykonać zapytanie
{
$offset = mt_rand()%$max; //losujemy "offset", najszybszy sposób korzystania z mt_rand() z ograniczeniem
$sql= mysql_query("SELECT [$kolumny] FROM [$tabela] where id >= $offset limit [$rozmiar_paczki]");
while ($row = mysql_fetch_array($sql)) // zapisujemy wyniki
{
$temp[] = $row[0];
}
}

Oczywiście to rozwiązanie działa na tabeli, która posiada klucz główny. Nadal jest czasochłonna procedura zliczania ilości elementów lecz później zyskujemy sporo czasu. Wybieranie z Id >= wylosowanemu offsetowi zabiera naprawdę mało czasu i pamięci serwera, gdyż wybieramy z tabeli tylko te elementy, które chcemy i nic ponadto. Jest jeden minus, gdy usuniemy pewne bloki Id to prawdopodobieństwo wylosowania elementów graniczących z tymi blokami wzrasta, a możliwość wylosowania elementów na końcu zbioru spada znacznie. Jednak nie zapominajmy, że działamy na bardzo dużym zbiorze danych więc do większości zastosowań to rozwiązanie wystarczy. No prawie wystarczy ;). Jeżeli chcemy otrzymać tylko unikalne wyniki to widać, że istnieje duże prawdopodobieństwo otrzymania pewnych duplikatów. Co wtedy? Rozwiązanie jest proste:

$temp = array_unique($temp);

Tak tylko teraz pojawia się problem :). Mamy za mało wpisów. Trzeba nareperować:


while (count($temp) < [$ilość_elementów])
{
$offset = mt_rand()%$max;
$sql= mysql_query("SELECT [$kolumny] FROM [$tabela] id >= $offset limit [$rozmiar_paczki]");
while ($row = mysql_fetch_array($sql))
{
$temp[] = $row[0];
}
$temp = array_unique($temp);
}

$temp = array_chunk($temp,[$ilość_elementów]);
$temp = $temp[0];
powtarzamy całą operacje do skutku i na koniec obcinamy do odpowiedniej ilości elementów. Przy ilości danych pobieranych bliskiej do ilości rekordów w tablicy mogło by to trochę potrwać. Ale przykład ten jest zoptymalizowany pod duże rozbieżności :). Dodam, że rozmiar paczki musi być zbalansowany do ilości elementów, tak aby baza nie otrzymała zbyt wielu zapytań. W tym celu należy znaleźć złoty środek (opracowuje go jeszcze ;)).

Takim oto kodem w całości:

$sql= mysql_query("SELECT count(id) FROM [$tabela]");
$row= mysql_fetch_array($sql);
$max= $row[0];
$temp = array();
for ($i=0; $i<[$ilość_elementów]/[$rozmiar_paczki]; $i++)
{

$offset = mt_rand()%$max;
$sql= mysql_query(”SELECT[$kolumny] FROM [$tabela] where id >= $offset limit [$rozmiar_paczki]”);
while ($row = mysql_fetch_array($sql))
{
$temp[] = $row[0];
}
}

$temp = array_unique($temp);

while (count($temp) < [$ilość_elementów])
{
$offset = mt_rand()%$max;
$sql= mysql_query(”SELECT[$kolumny] FROM [$tabela] where id >= $offset limit [$rozmiar_paczki]”);
while ($row = mysql_fetch_array($sql))
{
$temp[] = $row[0];
}
$temp = array_unique($temp);
}

$temp = array_chunk($temp,[$ilość_elementów]);
$temp = $temp[0];
shuffle($temp); // w $temp mamy żądaną ilość elementów przetasowanych

Otrzymujemy 10 000 unikalnych elementów z tabeli o rozmiarze ok 1 250 000 w czasie ok. 5s. przy rozmiarze paczki 50. Aby uzyskać pełną losowość występowania rekordów w wyniku proponuje funkcje shuffle(), które przetasuje całość elementów i nie zwiększy zauważalnie czasu pobierania danych.

Jako, że to mój pierwszy wpis to jeżeli ktoś to czyta ;) to zachęcam do komentarzy.

EDIT:

Widzę, że jest pewne zainteresowanie więc podpowiadam, że znacznie można jeszcze przyspieszyć pobieranie danych przechowując ilość zapisanych rekordów… wtedy zamiast liczyć za każdym razem pobieramy jedna wartość (liczenie najwięcej zajmuje). Wystarczy zdefiniować dwa triggery do bazy ON DELETE i ON INSERT, które odpowiednio bedą modyfikowały tę wartość… powodzenia :)

Nowy start

by 7uk3r0n1n, January 17th, 2008 | 2 Comments

Z braku czasu i chęci oraz dzięki zauważeniu bezcelowości tamtego rozwiązania… będzie WordPress :P