Źródła niektórych bibliotek .NET Framework będą dostępne
Autor: Marcin Guzowski | Data:
05.10.2007, 19:31
| Kategorie: Platforma .NET
| Komentarze (0)
| Ślady (0)
Microsoft zdecydował się udostępnić kod źródłowy wraz z komentarzami niektórych bibliotek .NET Framework:
- .NET Base Class Libraries (System, System.IO, System.Collections, System.Configuration, System.Threading, System.Net, System.Security, System.Runtime, System.Text i pewnie jeszcze kilku innych), - ASP.NET (System.Web), - Windows Forms (System.Windows.Forms), - ADO.NET (System.Data), - XML (System.Xml), - WPF (System.Windows). Kod źródłowy zostanie opublikowany na licencji Microsoft Reference License (Ms-RL) wraz z wydaniem .NET Framework 3.5 i Visual Studio 2008. Udostępnienie wyżej wymienionych bibliotek będzie polegać na tym, że w Visual Studio 2008 pobierzemy symbole z jednego z serwerów (pewnie source.msdn.microsoft.com). Więcej informacji: ScottGu's Blog: Releasing the Source Code for the .NET Framework Libraries Microsoft Reference License (Ms-RL) 3 x 2008, czyli premiera Windows Server 2008, SQL Server 2008 i Visual Studio 2008
Autor: Marcin Guzowski | Data:
11.07.2007, 18:51
| Kategorie: MS SQL Server, Platforma .NET, Różne
| Komentarze (0)
| Ślady (0)
Na międzynarodowej konferencji dla przeszło 10 tysięcy firm partnerskich (Worldwide Partner Conference, WPC) w Denver Microsoft ogłosił, że premiery nowych wersji znanych produktów - systemu operacyjnego Windows Server 2008 (codename Longhorn), platformy bazodanowej SQL Server 2008 (codename Katmai) i zintegrowanego środowiska programistycznego Visual Studio 2008 (codename Orcas) odbędą się 27 lutego 2008 roku w Los Angeles. Wydarzenie to zapoczątkuje serię mniejszych konferencji na poziomie krajowym, na których prezentowane będą nowe produkty.
Więcej informacji: Microsoft PressPass: Microsoft Executives Outline Next-Generation Business Opportunities for Partners With New Products, Tools and Programs Enterprise Library 3.0
Autor: Marcin Guzowski | Data:
13.04.2007, 09:21
| Kategorie: Platforma .NET
| Komentarze (0)
| Ślady (0)
Na początku kwietnia Microsoft udostępnił trzecią wersję pakietu bibliotek Enterprise Library. EntLib to produkt, który ma ułatwiać developerom implementowanie standardowych funkcjonalności (jak np. cacheowanie) i pomóc w rozwiązywaniu najczęstszych problemów podczas tworzenia dużych aplikacji. Pakiet składa się z 8 bloków podstawowych:
- Caching Application Block - Cryptography Application Block - Data Access Application Block - Exception Handling Application Block - Logging Application Block - Policy Injection Application Block - Security Application Block - Validation Application Block EntLib wymaga co najmniej .NET Framework 2.0. Do skorzystania z niektórych grup funkcjonalności (Application Block Software Factory, Validation Application Block WCF i Exception Handling Application Block WCF) potrzebny jest .NET Framework w wersji 3.0. Więcej informacji i pobieranie: MSDN: Enterprise Library Download: Enterprise Library 3.0 Przetwarzanie wyrażeń logicznych
Autor: Marcin Guzowski | Data:
11.02.2007, 15:02
| Kategorie: Świat Perla, MS SQL Server, Platforma .NET, Różne
| Komentarze (0)
| Ślady (0)
Ogromna większość technologii programistycznych (języków programowania, języków skryptowych itp.) zakłada specyficzny sposób przetwarzania wyrażeń logicznych zawartych najczęściej w różnego typu instrukcjach warunkowych (IF, WHILE, FOR). Chodzi o to, że zdanie logiczne składające się z kilku wyrażeń, np:
A OR B OR C jest uwzględniane tylko do momentu, w którym da się określić wartość całego wyrażenia. W powyższym przykładzie moment ten nastąpi już w sytuacji, w której wartość logiczna wyrażenia A będzie prawdziwa (alternatywa jest prawdziwa, gdy prawdziwy jest jeden z jej elementów). Głównym uzasadnieniem takiej obsługi są kwestie wydajnościowe i praktyczne. Opisane podejście do przetwarzania warunków ma jednak szereg konsekwencji, które warto sobie uświadomić. Postaram się zwrócić na nie uwagę bardziej szczegółowo prezentując implementację zasygnalizowanego zagadnienia w kilku środowiskach. Practical Extraction and Report Language (Perl) Spójrzmy na poniższy skrypt: #!/usr/bin/perl Interesuje nas odpowiedź na pytanie, czy funkcja func() zostanie w ogóle wywołana. Otóż - zgodnie z tym, co napisałem we wstępie - nie zostanie. Nie ma potrzeby sprawdzania wyrażenia z funkcją, gdyż już na podstawie nieprawdziwości wyrażenia $a != 1 (1 != 1) można stwierdzić, że całe zdanie warunku jest fałszywe. Skrypt drukuje więc: 0 Trzeba o tym pamiętać umieszczając funkcję w logice instrukcji warunkowych. W rzeczywistości to właśnie opisana obsługa warunków umożliwia stosowanie konstrukcji typu: if (defined $zmienna and $zmienna == 5) { } Gdyby za każdym razem przetwarzane było całe wyrażenie, to przy zastosowanym use warnings; dochodziłoby do monitu: Use of uninitialized value in numeric eq (==) at (...) zawsze wtedy, kiedy $zmienna byłaby undef. Platforma .NET (C#) Obsługa jest analogiczna, poniższy program drukuje 0. using System; Podobnie jak w Perlu, w C# (i innych językach .NETowskich) dzięki specyficznej obsłudze wyrażeń logicznych możliwe jest stosowanie konstrukcji: if (obj != null && obj.property == 2) { } Różnica między C# i Perlem polega jednak w tym przypadku na tym, że o ile w Perlu użycie niezainicjalizowanej zmiennej skutkuje co najwyżej ostrzeżeniem (warning level), o tyle w .NET użycie nieistniejącego obiektu kończy się rzuceniem wyjątku NullReferenceException(). C/C++ Przykładowy kod w przypadku C: #include < stdio.h> Jeżeli w powyższym kodzie pierwsze wyrażenie składowe warunku IF zostanie zmienione na 1 == 1, to większość kompilatorów w ogóle nie uwzględni drugiego wyrażenia alternatywy (z funkcją func()) - skompiluje więc warunek jako zawsze prawdziwy. Można się o tym łatwo przekonać zamieniając dodatkowo nazwę funkcji w warunku na taką, która nie istnieje: if (1 == 1 || nie_mam_definicji(&count) == 2) { } W obu przypadkach (zmieniony i niezmieniony kod przykładowy) skompilowany program zwraca 0. JavaScript Obsługa jest analogiczna: <SCRIPT TYPE="text/javascript"> Alert prezentuje wartość 0. Microsoft SQL Server Jeżeli wywołamy poniższy T-SQL: SELECT 0/0 SQL Server natychmiast rzuci błędem: Msg 8134, Level 16, State 1, Line 1 Kiedy jednak dzielenie przez 0 znajdzie się w odpowiednim warunku logicznym: IF (1=1 OR 1=0/0) błąd nie występuje, gdyż nie dochodzi do wykonania wadliwego kodu. O ile w przypadku Perla, C czy C# specyficzna ewaluacja warunków logicznych jest czymś pozytywnym, o tyle w świecie baz danych prowadzi do pewnych niekonsekwencji. Trzeba pamiętać, że SQL Server i inne RDBMS implementują logikę trójwartościową (three-valued logic, 3VL). Przestrzeń nie ogranicza się więc do wartości TRUE i FALSE, lecz składa się na nią TRUE, FALSE i UNKNOWN. Może więc dojść do sytuacji, że kiedy - ze względu na operację z NULLem - warunek powinien mieć wartość logiczną UNKNOWN, w praktyce zwraca wartość prawdy. Dokładnie taka sytuacja ma miejsce w poniższym przykładzie: DECLARE @a int; Warto o tym pamiętać, gdyż NULLe i stany nieokreśloności mogą generować sporą ilość trudno wykrywalnych problemów. Sposób ewaluacji wyrażeń logicznych jest analogiczny w stosunku do wyżej opisanego w przypadku wszystkich znanych mi technologii (języków). Wiedza o takim sposobie obsługi jest więc całkiem wskazana tym bardziej, że umożliwi ona zapisywanie skomplikowanych warunków logicznych w sposób bardziej wydajny - czyli taki, aby sterując kolejnością wyrażeń składowych jak najwcześniej dało się zaprzeczyć lub uznać za prawdziwy cały warunek. Oczywiście ten swoisty tuning wyrażeń logicznych może mieć miejsce wyłącznie w środowisku, które respektuje kolejność wykonywania wyrażeń składowych zgodnie z ich występowaniem w kodzie (od lewej do prawej). Jest to powszechny standard, ale np. SQL Server się do niego nie stosuje. Garbage collection i słabe referencje (weak references)
Autor: Marcin Guzowski | Data:
06.01.2007, 18:08
| Kategorie: Platforma .NET
| Komentarze (0)
| Ślady (0)
Różne środowiska uruchomieniowe, w tym także CLR platformy .NET, wykorzystują mechanizm automatycznego zarządzania pamięcią, określany powszechnie jako "odśmiecanie pamięci" (garbage collection). Podstawowym celem zastosowania garbage collection była chęć uwolnienia dewelopera od obowiązku ciągłego myślenia w kategorii skończoności zasobów o przydziale i zwalnianiu dostępnej pamięci. Wpisuje się to oczywiście w ogólną koncepcję tworzenia oprogramowania wg podejścia RAD (Rapid Application Development). Zgodnie z założeniami, w środowisku .NET alokacją i zwalnianiem pamięci zajmuje się specjalny mechanizm - tzw. garbage collector (GC), a programista powinien skupić się na funkcjonalności aplikacji. Nie oznacza to jednak, że możemy zupełnie zapomnieć o kwestiach dotyczących pamięci. GC funkcjonuje w oparciu o zestaw reguł, na podstawie których podejmuje określone działania. Naturalnie reguły te nie są równie efektywne w każdej z możliwych sytuacji, dlatego właśnie świadomy deweloper powinien nauczyć się tak pisać swój kod, żeby w pośredni sposób wpływać na przewidywalne zachowania garbage collectora.
Chciałbym zwrócić uwagę na kilka kwestii związanych z automatycznym zarządzaniem pamięcią na platformie .NET. Tematyka jest bardzo szeroka i wieloaspektowa, dlatego poniższe informacje mogą stanowić jedynie wstęp do bardziej dogłębnej analizy tematu. Pamięć w sensie funkcjonalnym podzielić możemy na stos (stack) i stertę zarządzaną (managed heap). Typy bezpośrednie (value types, czyli np. zmienne w metodzie) alokowane są na stosie. GC nie ma z nimi za wiele pracy - po opuszczeniu metody pamięć jest w prosty i natychmiastowy sposób zwalniana. Wszystko komplikuje się w przypadku typów referencyjnych, które alokowane są na stercie. Każde utworzenie nowego obiektu powoduje zarezerwowanie określonego obszaru pamięci na stercie (przesuwany jest także wskaźnik alokacji NextObjPtr, wskazujący następny dostępny adres). O ile moment tworzenia obiektu jest jednoznaczny i trywialny do określenia, o tyle identyfikacja obiektów już niepotrzebnych to działanie o wiele bardziej złożone. Zadanie to GC realizuje poprzez cykliczne sprawdzanie, które obiekty nie są osiągalne z żadnego zasięgu w programie. Odbywa się to na zasadzie wstępnej negacji - początkowo wszystkie obiekty uznawane są za martwe, następnie GC z listy śmierci usuwane te, które w danym momencie mogą być osiągnięte przez kod aplikacji. Pozostałe obiekty przeznaczone są do unicestwienia. Podczas okresowej aktualizacji sterty GC zwalnia bloki pamięci odnoszące się do martwych obiektów. Dodatkowo scala pozostałe bloki tak, by nie pozostawały między nimi żadne wolne przestrzenie. Wiąże się to oczywiście z koniecznością aktualizacji wskaźnika alokacji i koniecznością przeadresowania wszystkich referencji do obiektów, gdyż po migracji bloków zmianie ulegają adresy pamięci. Operacje wykonywane przez GC są dla wnętrzności naszego programu dość rewolucyjne i kosztowne pod względem wydajności. Podczas działania GC może wystąpić chwilowa niepoprawność referencji, pamięć musi więc pozostawać niedostępna dla aplikacji, co jest realizowane przez wstrzymanie wszystkich jej wątków. Ze względu na opisaną charakterystykę pracy i kosztowność operacji, GC uruchamiany jest zasadniczo dopiero w sytuacji braku pamięci na stercie. Algorytm garbage collection działa w rzeczywistości w nieco bardziej skomplikowany sposób, uwzględniając m.in. tzw. generacje. Możliwe jest także wymuszone uruchomienie GC z kodu aplikacji (System.GC.Collect()). Wymienione kwestie, jak też inne szczegóły wykraczają jednak poza zakres tego powierzchownego artykułu - zainteresowanych zapraszam do zapoznania się z linkami zebranymi poniżej. Trzeba pamiętać, że GC zajmuje się zwalnianiem pamięci zajmowanej przez martwe obiekty, a nie zwalnianiem wszystkich zasobów przez te obiekty wykorzystywanych. Sami więc musimy zadbać o zwolnienia zasobów niezarządzanych (plikowych, sieciowych, sprzętowych), np. otwartego połączenia do bazy danych. Nie chodzi tutaj wyłącznie o tzw. finalizację (zaimplementowanie finalizatora klasy), która w wielu sytuacjach może okazać się mało efektywna. Lepszym wyjściem będzie oprogramowanie metod Close() i Dispose(), czy stosowanie bloku using. Ciekawe możliwości oferują tzw. słabe referencje (weak references). Nie jest to pomysł ani nowy, ani specyficzny wyłącznie dla platformy .NET. Słabe referencje spotykamy również w innych technologiach z mechanizmem typu garbage collection (jak Java czy Perl). Dla jednoznaczności warto uściślić, że silna referencja do obiektu (strong reference) występuje w sytuacji, kiedy obiekt może być osiągnięty z kodu aplikacji. W sytuacji silnej (zwykłej) referencji obiekt jest więc poza zainteresowanie GC. Słaba referencja natomiast to swoisty kompromis - obiekt jest co prawda dostępny dla aplikacji (która może uzyskać do niego silną referencję), ale w każdym momencie GC może go unicestwić. Pozornie może się wydawać, że nie ma to wielkiego sensu. Są jednak sytuacje, w których opisany kompromis jest całkiem akceptowalny. Słabe referencje świetnie nadają się do obiektów, które zajmują duży obszar pamięci, ale mogą być łatwo odtworzone. Wprowadza to swoistą elastyczność obsługi do naszej aplikacji. Kiedy zabraknie pamięci, obiekt ze słabą referencją zostanie unicestwiony przez GC i na stercie przybędzie potrzebnej w danym momencie wolnej przestrzeni. Jeżeli obiekt będzie potrzebny ponownie, zostanie w prosty sposób zrekonstruowany. W sytuacji dostatecznej ilości wolnej przestrzeni na stercie, obiekt nie zostanie zniszczony, aplikacja będzie więc go mogła użyć natychmiast po wykorzystaniu słabej referencji. Słabych referencji nie należy stosować przy małych obiektach jak też nie są one remedium na wszystkie problemy wydajnościowe aplikacji - w każdym razie na pewno nie zastąpią rozsądnego i przemyślanego cacheowania. Więcej informacji: MSDN: Garbage Collection: Automatic Memory Management in the Microsoft .NET Framework MSDN: Garbage Collection—Part 2: Automatic Memory Management in the Microsoft .NET Framework MSDN: Using Weak References Deduplikacja danych: .NET vs Perl
Autor: Marcin Guzowski | Data:
16.11.2006, 22:39
| Kategorie: Świat Perla, Platforma .NET
| Komentarze (2)
| Ślad (1)
Systemy informatyczne przetwarzają coraz większe ilości danych, w naturalny sposób pojawia się więc coraz większa potrzeba ich automatycznej analizy i obróbki. Deweloperzy związani z bazami danych muszą tworzyć specyficzne, dedykowane rozwiązania, a wybór odpowiedniej technologii to praktycznie klucz do sukcesu. Chciałbym porównać dwie wybrane platformy - .NET i Perl - w hipotetycznym scenariuszu automatycznego przetwarzania danych.
Wspomniany scenariusz zakłada potrzebę wyznaczenia rekordów podobnych w bazie klientów, a dokładniej - w tabeli, która zawiera 10000 wierszy z danymi teleadresowymi (przykładowe kolumny: nazwa, miejscowość, adres, kod, nip). Dane w bazie są zwielokrotnione, tzn. kilka rekordów w rzeczywistości opisuje jednego i tego samego klienta (zapisanego oczywiście w różny sposób, np. "FIRMA HERKULES", "HERKULES S.C.", "HERKULES - SKLEP"; analogicznie z danymi adresowymi: "WIEJSKA 15", "ULICA WIEJSKA" itd.). Aby zrealizować cel, do tabeli zostanie dodana kolumna unikalnego identyfikatora, a algorytm zapełni ją odpowiednimi wartościami, przydzielając rekordom dostatecznie podobnym taki sam identyfikator. Zakładamy ponadto warunek brzegowy (minimalizacja ryzyka błędu): rekordy oznaczone jako podobne muszą posiadać identyczny NIP. Zadanie opisane wyżej to klasyczna deduplikacja danych. Od prawie 2 lat zajmuję się m.in. procesami inteligentnej analizy, przetwarzania danych i obserwuję w ostatnim czasie znaczący, dynamiczny wzrost popularności tej tematyki. Złoty wiek różnorodnych automatów właśnie się rozpoczął. Wracając do naszego scenariusza, można sobie wyobrazić co najmniej kilka koncepcji algorytmu deduplikacji, oczywiście każdy z nich ma swoje mocne i słabe strony. Skupiamy się na technologii, a nie na funkcjonalnościach - więc dodam tylko, że do oceny zgodności poszczególnych pól użyłem metody Levenshtein-Distance (google zaprasza zainteresowanych). Środowisko testowe wyglądało następująco: serwer Windows Server 2003 SE 32bit, baza danych SQL Server 2005 SP1, wszystko postawione na jednej maszynie (na której uruchamiane były również testowe implementacje). Jak widać środowisko zostało dobrane tak, żeby lekko faworyzować platformę .NET. Implementacja algorytmu w CLR (język C#) to klasyczna aplikacja obiektowa z providerem OLE DB (natywne rozwiązanie względem SQL Servera). Algorytm został również zaimplementowany w Perlu (wersja 5.8.8), dostępem do danych zajmował się moduł DBI działający na providerze ODBC. Mamy więc pojedynek technologii, za którą stoją miliardy dolarów w jej naturalnym środowisku - i - technologii open source, która dzięki wieloletniej pracy rzeszy ludzi została wysoce zoptymalizowana do przetwarzania danych, a wyrażenia regularne traktuje tak samo natywnie jak choćby instrukcję warunkową IF. Poniżej przedstawiam wyniki: (średni czas dla 3 prób) Wyraźnie zwyciężył więc Perl, który zadanie wykonał o 55% szybciej niż konkurent (jakość była jednakowa w obydwu przypadkach, zgodnie z założeniem). Nie pierwszy raz przekonałem się, że Practical Extraction and Report Language nie ma sobie równych wśród technologii do przetwarzania danych. Warto też dodać, że obydwie implementacje powstały w tak samo krótkim czasie, mimo że do stworzenia kodu w Perlu wykorzystałem zwykły edytor tekstowy, a do .NET - potężne Visual Studio 2005 z pełnym intellisense i innymi programistycznymi udogodnieniami. Bezpieczeństwo kodu źródłowego
Autor: Marcin Guzowski | Data:
11.11.2006, 14:36
| Kategorie: Bezpieczeństwo, Platforma .NET
| Komentarze (0)
| Ślady (0)
Platforma .NET dostarcza deweloperom wielu nowych możliwości, ułatwień i ulepszeń, także w aspekcie bezpieczeństwa - zwiększając tym samym ochronę szeroko pojętych dóbr intelektualnych. Współczesne organizacje poświęcają wiele energii dbając o to, by określona informacja nie dotarła do osób niepowołanych. Stosowane są zaawansowane metodyki bezpieczeństwa, szyfrowanie, ścisła identyfikacja zasobów, firewalle itd. Tymczasem dając użytkownikowi do ręki skompilowaną do kilku plików DDL i pliku EXE aplikację .NET - dajemy mu jednocześnie na talerzu co najmniej jej algorytmiczne tajemnice, a często także szereg innych cennych informacji.
Wszystkie .NETowskie asemblacje objęte są tzw. mechanizmem reflection, który jest interfejsem do pozyskania szczegółowych metainformacji dotyczących wszystkich klas w danej assembly. To cena, jaką płacimy m.in. za intellisense w Visual Studio. Wprawdzie self-desribing assemblies nie ujawniają własnego kodu MSIL (Microsoft Intermediate Language), jednak droga do jego pozyskania dla amatorów cudzego kodu źródłowego jest banalnie prosta. Jeszcze łatwiej natomiast zamienić instrukcje języka pośredniego na kod języka wyższego poziomu - C#, VB.NET czy managed C++. Razem z .NET Framework dostarczany jest IL Assembler - to oczywiste. Być może mniej oczywisty jest fakt, że wraz z .NET Framework SDK (dołączonym m.in. do Visual Studio), dostarczany jest także IL Disassembler. Wystarczy więc uruchomić plik lidasm.exe i już mamy okienkowy interfejs prowadzący wprost do kodu pośredniego dowolnej aplikacji .NET, nie robiąc przy tym kompletnie nic nielegalnego. IL Disassembler jest jednak troszkę toporny, w końcu dlaczego nie mielibyśmy od razu otrzymać kodu w dowolnym języku wyższego poziomu (do wyboru), wraz z całą hierarchią obiektów, typami, metodami w przyjaznym dla oka GUI? Nic bardziej prostszego, programów tego typu jest całkiem sporo. Wystarczy polecić Lutz Roeder's .NET Reflector (strona domowa). Na życzenie program ten wygeneruje nam w pełni funkcjonalny projekt, który natychmiast możemy otworzyć w Visual Studio. Okrutna prawda jest taka, że każdy program można poddać mniej lub bardziej skutecznej disasemblacji, przy czym jest to o wiele trudniejsze w przypadku binarki Win32, a o wiele łatwiejsze w przypadku aplikacji .NET (analogicznie: Javy czy Perla). Potwierdza to starą zasadę, że nie ma zabezpieczenia, którego nie dałoby się złamać. Jedyne co można zrobić, to maksymalnie utrudnić reverse engineering, mając nadzieję, że skutecznie zniechęci to ewentualnych zainteresowanych. Jeżeli już musimy udostępnić komuś bezpośrednio skompilowany program, to zadbajmy chociaż o maksymalne "zaciemnienie" jego kodu źródłowego. Można użyć do tego celu jednego z powszechnie dostępnych obfuscatorów, np. programu Dotfuscator (strona domowa, polecany przez Microsoft). Kod źródłowy zostanie wtedy odpowiednio zmodyfikowany: obfuscator zamieni nazwy zmiennych, obiektów, metod na niezrozumiałe dla człowieka sekwencje znaków, zaszyfruje wartości stringów, zastosuje instrukcje goto utrudniające zrozumienie kolejności instrukcji itp. Oczywiście wszystkie wymienione czynności nie będą wpływały na efekt działania skompilowanej aplikacji, chodzi tylko o jak największe skomplikowanie analizy kodu pozyskanego przez disasemblację. Trzeba jednak od razu zaznaczyć, że istnieje co najmniej kilka deobfuscatorów, które potrafią przywrócić kod do całkiem czytelnej formy... Szczerze mówiąc, nie ma dobrej metody na ochronę kodu aplikacji .NET, jeżeli fizycznie przekazujemy skompilowany program osobie trzeciej. Trzeba mieć to na uwadze projektując rozwiązania z zastosowaniem tej technologii. Nie zawsze jednak sytuacja wymaga takiego kroku - wtedy otwiera się obszar dla zastosowania technologii webowej lub usług terminalowych. Może i są to rozwiązania mniej wygodne dla użytkownika, ale nie ma przecież nic za darmo.
(Strona 1 z 2, łącznie 9 wpisów)
» następna strona
|
Kalendarz
KategorieSubskrybcjaInne blogiArchiwaMarzec 2010 (0)
Luty 2010 (0) Styczeń 2010 (0) Grudzień 2009 (0) Listopad 2009 (0) Październik 2009 (0) Wrzesień 2009 (0) Sierpień 2009 (0) Lipiec 2009 (0) Czerwiec 2009 (0) Maj 2009 (0) Kwiecień 2009 (0) Marzec 2009 (0) Luty 2009 (0) Styczeń 2009 (0) Grudzień 2008 (0) Listopad 2008 (0) Październik 2008 (0) Wrzesień 2008 (0) Sierpień 2008 (0) Lipiec 2008 (0) Czerwiec 2008 (0) Maj 2008 (0) Kwiecień 2008 (0) Marzec 2008 (0) Luty 2008 (0) Styczeń 2008 (0) Grudzień 2007 (0) Listopad 2007 (0) Październik 2007 (1) Wrzesień 2007 (0) Sierpień 2007 (0) Lipiec 2007 (1) Czerwiec 2007 (0) Maj 2007 (0) Kwiecień 2007 (1) Marzec 2007 (0) Luty 2007 (1) Styczeń 2007 (1) Grudzień 2006 (0) Ostatnie.... Starsze... Ostatnie wpisyPo 17. spotkaniu PLSSUG Lublin
czwartek, wrzesień 17 2009 Mac OS X Snow Leopard - pierwsze wrażenia niedziela, wrzesień 13 2009 PLSSUG Lublin: wakacyjna przerwa w spotkaniach niedziela, czerwiec 7 2009 15. spotkanie PLSSUG Lublin piątek, kwiecień 17 2009 SQL Server Standard 64bit - czy dziś znów się wyłoży? sobota, marzec 28 2009 14. spotkanie PLSSUG Lublin i kilka słów o grupie czwartek, marzec 5 2009 SQL Server 2008 Service Pack 1 CTP środa, luty 25 2009 SQL Server 2008 System Views Map niedziela, luty 15 2009 13. spotkanie PLSSUG Lublin czwartek, luty 12 2009 Windows 7 - co powie ryba niedziela, luty 8 2009 WyszukajLicencja |
|||||||||||||||||||||||||||||||||||||||||||||||||
© Marcin A. Guzowski 2006-2009
http://guzowski.info

