Żegnaj .NET World…

Po wielomiesięcznej przerwie postanowiłem odświeżyć „przyjaźń” z moim blogiem. Ten oto wpis jest prawdopodobnie końcem pewnego etapu w moim programistycznym życiu.

Pierwsza zmiana jest taka, że znalazłem, a właściwie to ona mnie znalazła, pracę. Kilka miesięcy temu stanąłem przed realnym wyborem swojej ścieżki zawodowej – pozostanie przy technologii .NET czy rozpoczęcie nauki czegoś dość odmiennego?? Podobno jeżeli ktoś potrafi programować to bez problemu nauczy się dowolnego języka (w granicach rozsądku ;)) czy też z łatwością zgłębi tajniki nowej technologii.

Mogę na dzień dzisiejszy śmiało powiedzieć, że jest to w sporej części prawda, bo oto przez ostatnie miesiące z ogromną przyjemnością zajmuję się implementacją aplikacji internetowych przy użyciu technologii dostarczanej przez firmę Adobe – Flex.

Druga zmiana wynikająca z pierwszej to moja decyzja o pozostaniu przy tym czym się aktualnie zajmuję. Platforma .NET oraz wszystko czego się nauczyłem obcując z technologiami Microsoft-u pozostanie już raczej tylko moim „hobby”. Jak dotąd nie żałuję rzucenia się na głęboką wodę i oby nic mojego dobrego samopoczucia wynikającego z obecnej pracy nie zmieniło. Trzecia zmiana jest konsekwencją pożegnania i dotyczy nie tylko nowej tematyki zamieszczanej tutaj treści, ale także samego tytułu który tak radośnie witał wszystkich odwiedzających moje skromne blogowe progi. ;) Myślę jednak, że jeszcze zdarzy mi się jak już wyżej napisałem „hobbystycznie” wspomnieć o swoich .NET-owych korzeniach.

Na koniec chciałbym podziękować społeczności skupiającej się wokół portalu codeguru.pl, mojemu nauczycielowi „Języków programowania”, dzięki któremu robię to co robię…

Dziękuję również koledze bojkar-owi, dzięki któremu się nie poddałem oraz koledze redliquid-owi, który swoim przykładem zachęca mnie każdego dnia w pracy do ciągłego pogłębiania wiedzy. :)

Żegnaj .NET World! Witaj nowe, nieznane… :)

Prosty błąd – proste rozwiązanie

Zmagam się od jakiegoś czasu z ASP .NET Web Service-ami. Utworzyłem nowy Web Service i postanowiłem zmienić nazwę pliku Web Servicu ze standardowego Service1 na ServiceAdmin. Zmiana przebiegła bezproblemowo po uruchomieniu otrzymałem taki oto błąd:

webserviceerror

Zgodnie ze wskazówkami błędu swoją uwagę skierowałem na plik .asmx – standardowo kliknąłem dwukrotnie w Visual Studio oczekując na pojawienie się magicznej xml-owej linijki. Niestety Visual Studio przekierował mnie do kodu Web Servicu. Po dobrych 10 minutach moje mało spostrzegawcze oczy po kliknięciu prawym przyciskiem myszy na plik ujrzały opcję: Open With… -> XML Editor:

<%@ WebService Language="C#" CodeBehind="ServiceAdmin.asmx.cs" Class="WBAdmin.Service1" %>

Visual Studio nie zrefaktorował atrybutu „Class” – wprowadziłem ręcznie to czego potrzebował kompilator podczas uruchamiania.

<%@ WebService Language="C#" CodeBehind="ServiceAdmin.asmx.cs" Class="WBAdmin.ServiceAdmin" %>

W przeglądarce ujrzałem magiczne „Hellow World”. ;)

Zewnętrzne źródło danych w raportach MS Access

Podczas praktyk studenckich które odbyłem kilka tygodni temu zapoznałem się z możliwościami tworzenia raportów w Microsoft Access. Pracowałem nad rozwoje oprogramowania raportującego. Jednym z postawionych przede mną zadań było stworzenie mechanizmu umożliwiającego wywoływanie procedur składowanych z MS SQL Server i podpięcie otrzymanych wyników do utworzonych wcześniej raportów. Uzyskane wyniki miałem „zapakować” w Visual Basic-owy twór zwany RecordSet-em i podpiąć go bezpośrednio do raportu.

Uruchomienie procedury składowanej z poziomu MS Access utworzonej np. w MS SQL Server umożliwia tzw. kwerenda przekazująca. Cały ciężar związaną z wykonaniem zapytania czy też wspomnianej już procedury składowanej spada na „barki” silnika bazodanowego do którego zostanie wysłane polecenie. Mamy proste narzędzia do tworzenia raportów w MS Access – natomiast filtrowanie i przechowywanie ogromnych ilości danych przed udostępnienem ich w raporcie pozostawiamy większemu silnikowi bazodanowemu. – I to wszystko dzięki magicznej kwerendzie przekazującej. :)

Kod tworzący tymczasowo taką kwerende i jej wywołanie przedstawia się następująco:

Funkcja tworząca i wykonująca zapytanie SQL lub procedure składowaną.

'qSQL = Zapytanie do bazy danych
'return RecordSet
Public Function ExecutePassThruQuery(qSQL As String) As Recordset
    Dim db As DAO.Database
    Dim qryDef As DAO.QueryDef
    Dim recSet As DAO.Recordset
    Dim queryName As String

    On Error GoTo ErrorHandling:
    'Obiekt bazy danych
    Set db = CurrentDb

    'Nazwa tymczasowej kwerendy przekazujacej
    queryName = "tempQuery"
    'Usuniecie kwerendy jesli istnieje
    RemovePassThruQueryIfExists (queryName)

    'Utworzenie nowej kwerendy przekazujacej
    Set qryDef = db.CreateQueryDef(queryName)

    qryDef.ReturnsRecords = True
    'polaczenie z baza danych
    qryDef.Connect = connectionString
    qryDef.SQL = qSQL

    'Zwraca obiekt Recordset-u z danymi, w przeciwnym wypadku zwraca Nothing
    Set ExecutePassThruQuery = qryDef.OpenRecordset(dbOpenSnapshot)

    Set db = Nothing
    Set qryDef = Nothing
    Set recSet = Nothing

    Exit Function
ErrorHandling:
    MsgBox Err.Description
End Function

Funkcja wywołująca pracedure składowaną (wykorzystuje powyższą funkcję do utworzenia i wywołania bezpośrednio na bazie danych procedury) – wzasadzie tworzy specyficzny string w postaci np. „nazwa_procedury parametr1, parametr2, parametr3″.

'params = kolekcja parametrow procedury skladowanej jesli jakies przyjmuje
'procName = nazwa procedury skladowanej
'return DAO.RecordSet
Public Function CallStoredProcedure(procName As String, params As Collection) As Recordset
    Dim recSet As DAO.Recordset
    Dim queryName As String
    Dim counter As Integer

    On Error GoTo ErrorHandling:

    queryName = "tempQuery"

    'Dolaczam parametry do procedury
    If Not params Is Nothing Then
        If params.Count > 0 Then
            procName = procName & " " & CStr(params(1))
            For counter = 2 To params.Count
                procName = procName & ", " & CStr(params.Item(counter))
            Next counter
        End If
    End If

    'Wywoluje Funkcje zwracajaca rezultat wykonanej procedury skladowanej
    Set recSet = ExecutePassThruQuery(procName)

    Set CallStoredProcedure = recSet

    Set recSet = Nothing

    Exit Function
ErrorHandling:
    MsgBox Err.Description
End Function

Dodatkowo utworzyłem procedurę usuwającą tymczasową kwerende przekazującą.

'Usuwa tymczasowa kwerende
'queryName = nazwa kwerendy do usuniecia
Private Sub RemovePassThruQueryIfExists(queryName)
    Dim qryDef As QueryDef
    Dim db As Database

    On Error GoTo ErrorHandling
    Set db = CurrentDb

    For Each qryDef In db.QueryDefs
        If qryDef.Name = queryName Then
            db.QueryDefs.Delete (qryDef.Name)
            Exit For
        End If
    Next

    Set qryDef = Nothing
    Set db = Nothing
    Exit Sub
ErrorHandling:
    MsgBox Err.Description
End Sub

Załóżmy, że wywoływana procedura składowana w MS SQL Server ma nazwę „mojaProcedura” i pobiera dwa parametry typu VARCHAR. Wartości parametrów które chcemy przekazac do procedury są następujące: param1 = „ala”, param2 = „ola”. Kwerenda przekazująca w swoim wnętrzu miała by string w takiej oto postaci: „mojaProcedura ala, ola”.

Wywołanie:

Dim recSet As DAO.Recordset
Dim col As New Collection

col.Add "ala"
col.Add "ola"

Set recSet = CallStoredProcedure "mojaProcedura", col

W zasadzie to wszystko – tyle wystarczy, aby otrzymac obiekt RecordSet-u który następnie możemy bez żadnych przeszkód podpiąć do utworzonego wcześniej w MS Access raportu. :)

To co dała mi praktyka i to czego nie dała mi szkoła

Majowym wpisem pod tytułem „Pierwsza praca” rozpocząłem poszukiwania miejsca gdzie mógłbym odbyć praktykę zawodową. Wiele firm zajmujących się produkcją oprogramowania realizuje programy letnich praktyk studenckich skierowane do studentów ostatnich lat studiów. Kierując się bardzo pomocnymi komentarzami pod wspomnianym wyżej wpisem rozpocząłem wysyłanie CV. Zakładałem, że na drodze do upragnionych pierwszych poczynań programistycznych stanie mi rozmowa kwalifikacyjna (to raczej naturalne), problem znalezienia lokum w mieście do którego się udam itd. – Jednak nie przypuszczałem, że dodatkowo uczelnia na której studiuje (PWSZ w Białej Podlaskiej) dołączy do tej listy.

Szanse sprawdzenia swoich umiejętności dała mi lubelska firma „UHC CompuGROUP holding” – zajmująca się tworzeniem oprogramowania dla sektora medycznego. Określiłbym, że rekrutacja odbyła się w dwóch etapach – przesłanie CV zakończyło się prośbą o dostarczenie „próbek kodu” – aplikacji które napisałem do tej pory. Następnie po kilkudniowej ciszy otrzymałem telefon i odbyła się 2,5 godzinna rozmowa wstępna :). Kilka dni później dowiedziałem się – kto będzie moim opiekunem praktyk oraz do jakiego działu zostałem przydzielony (Dział Systemów Ekonomicznych). Pozostało mi dopiąć kwestie formalne o czym napiszę szerzej pod koniec.

Moim głównym celem było zmierzenie się z realnymi problemami na stanowisku programisty. Otrzymałem pierwsze zadanie – opiekun rzeczowo wytłumaczył mi co mam zrobić, jakiego wyniku oczekuje. Moje potknięcia i niedociągnięcia były traktowane z pełną wyrozumiałością, co niesamowicie mnie motywowało do cięższej pracy. Miałem czas na naukę, nie obawiałem się pytać nawet o najgłupsze rzeczy, atmosfera panująca w UHC przerosła moje najśmielsze oczekiwania. Mimo, że nie do końca zajmowałem się tym czym bym chciał – wcale mi to nie przeszkadzało! To co robiłem sprawiało mi ogromną przyjemność. :)

Praktyki uzmysłowiły mi, że jeżeli trafie w przyszłości do firmy takiej jak UHC to szybko się rozwinę. Szukajcie właśnie takiej pozytywnej atmosfery gdy stawiacie pierwsze kroki ku wymarzonej pracy czy też praktyki. Polecam przeczytać wpis Procenta – dzięki któremu zwracałem uwagę na wszystko co się wokół dzieje już podczas rozmowy kwalifikacyjnej.

Pozdrawiam i jeszcze raz dziękuję Markowi, Tomkowi, Andrzejowi, Gabrysiowi i Kamilowi za wspaniałą atmosferę i to wszystko czego się od Was nauczyłem. :)

Jak już wspomniałem największą przeszkodą do odbycia upragnionych praktyk była uczelnia na której studiuje. W PWSZ w Białej Podlaskiej studenci II roku na kierunku informatyka mają obowiązek odbycia 4 tygodniowej praktyki studenckiej – wypełniłem ten obowiązek jednak miejsce praktyk odbiegało dalece od moich oczekiwań. Byłem świadomy, że większość firm tworzących oprogramowanie przyjmuję tak naprawdę studentów III roku, aby mogli się zmierzyć z realiami programistycznymi. Postanowiłem fakt ukończenia III roku uwieńczyć zdobyciem miejsca gdzie postawie pierwsze kroki w prawdziwej pracy.

Poproszono mnie w firmie UHC o umowę na praktyki z moją uczelnią – pomyślałem, że nie będzie z tym problemu mimo, że będą to moje fakultatywne (ponadprogramowe) praktyki. Zadzwoniłem, więc do Działu Spraw Studenckich skąd skierowano mnie do Działu Praktyk.

Odpowiedz Pani kierownik działu: Nie wydajemy umowy na praktyki ponadprogramowe.

Nie straciłem jeszcze nadziei i zgodnie z podpowiedzią z firmy zadzwoniłem do Biura Karier które na niektórych uczelniach podpisuję takie umowy
i nie ma z tym najmniejszego problemu.

Odpowiedz biura karier: Jest Pan pierwszą osobą pytająca o takie rzeczy. Proszę się skierować do Działu Praktyk. :/

Ostatnia deska ratunku – napisałem do prorektora uczelni. Pismo wróciło do działu praktyk i zgadnijcie co ? :) Żal.pl – Odpowiedź identyczna jak wyżej – Nie wydajemy bo…. Ciekaw jestem jaką opinie wyraził Pan prorektor pod moim podaniem – Jeśli w ogóle jakąś wyraził… Nakreśliłem odpowiednim osobom w firmie całą sytuację – przesłano mi firmowy druk umowy między uczelnią, a UHC z którym osobiście (jak dotąd załatwiałem wszystko telefonicznie) udałem się na uczelnie. Odwiedziłem Biuro Karier, skąd powędrowałem do Instytutu Zarządzania (zabawnie ;)) tam Pani poinformowała mnie, że za dwa dni przekaże moją umowę odpowiedniej osobie.

Uwaga teraz najlepsza część tej parodii – W tym samym czasie w firmie ktoś stanął „na głowie” i znalazł sposób, aby podpisać ze mną umowę z wyłączeniem uczelni. Wróciłem do domu przeczytałem maila z tą informacja i sprawa była załatwiona. W mojej głowie pojawiła się myśl – skoro mam już wszystko załatwione to sprawdzę jednak czy uczelnia pomoże w rozwoju swojemu studentowi i podpisze przedłożony druk. Mijają dwa dni – docieram na uczelnie o wyznaczonej godzinie, zgłaszam się do przemiłej Pani i… – „Ojej zapomniałam, ale zaraz zaniosę to Pani doktor..” :) – Uśmiechnąłem się tylko – Bez komentarza… Pani doktor zerknęła i poleciła mi iść z tym do dyrektora instytutu informatyki – paranoja. :) Wziąłem umowę – zrobiłem
z niej ładną kulkę i wyrzuciłem do kosza.

Oto w jaki sposób PWSZ w Białej Podlaskiej pomogło mi odbyć praktyki studenckie, oto jak władze uczelni wsparły moją własną inicjatywę, oto
w jaki sposób wsparły moją chęć rozwoju.

Brawo PWSZ!

Tylko dzięki postawie odpowiednich osób w firmie UHC nie kosztowało mnie to, więcej nerwów za co Bardzo Dziękuję.

Pierwszy krok w stronę pracy inżynierskiej

Postanowiłem przerwać delikatna ciszę w moich poczynaniach blogowych spowodowana sesją egzaminacyjną oraz trwającymi jeszcze upragnionymi praktykami zawodowymi o których szerzej wspomnę w najbliższym wpisie. :) Przede mną ostatni semestr studiów co powoduje, że zaczynam rozmyślać nad częścią praktyczną mojej pracy inżynierskiej. Zamierzam napisać niewielki system do tworzenia i przeprowadzania testów sprawdzających więdzę. Jakiś czas temu zainteresowałem się architekturą SOA (Service Oriented Architecture) – spróbuję niebawem głębiej przyjżeć się jej aspektom i wpleść pewne jej założenia do swojego projektu. Na dzień dzisiejszy w zgłębianiu wiedzy wspomagać mnie będzie ta oto książka:

Service Oriented Architecture For Dummies

Dodatkowo w zakamarkach mojej głowy pojawiają się takie oto technologie:

  • ADO. Entity Framework, Nhibernate
  • Web Services
  • MS SQL Server 2008
  • UML

To wszystko na początek – bez specjalnego rozwijania co i jak zostanie stworzone. Być może jakieś problemy które napotkam i rozwiążę znajdą się tutaj szczegółowo opisane. Trzymajcie kciuki drodzy czytelnicy za moje skromne inżynierskie przedsięwzięcie. ;)

Zabawa w szyfrowanie – RSA

W ramach zaliczenia laboratorium jednego z przedmiotów szkolnych miałem za zadanie napisać niewielki programik szyfrujący. Wybrałem szyfr RSA – jak podaje wikipedia jego nazwa jest akronimem utworzonym z pierwszych liter nazwisk jego twórców – Rivest, Shamir, Adleman. Szyfrowanie i odszyfrowanie tekstu z wykorzystaniem RSA nie jest procesem zbyt skomplikowanym – wymaga jednak operowania dość dużymi liczbami pierwszymi co zmusiło mnie do rezygnacji ze standardowego typu int w C# który miał za mały zakres. W bezdennych zasobach internetowych znalazłem strukturę którą wykorzystałem w swojej implementacji -> BigInt.

Etapy szyfrowania umożliwiające zakodowanie i odkodowanie tekstu:

  1. Wylosuj dwie duże liczby pierwsze p i q
  2. Oblicz n = p * q
  3. Oblicz phi = (p – 1) * (q – 1)
  4. Oblicz e -> Para (e, n) tworzy klucz publiczny wykorzystywany do szyfrowania
  5. Oblicz d -> Para (d, n) tworzy klucz prywatny wykorzystywany do odszyfrowania
  6. Szyfrowanie znaku:
    • Zamiana znaku na kod Ascii
    • Oznaczmy c jako zaszyfrowany znak c = asciiNume mod n
  7. Odszyfrowanie znaku:
    • Aby otrzymać na powrót zaszyfrowany znak: t = cd mod n

Zamiana znaku na kod Ascii i na odwrót:

          char ch = "A";
          int asciiNum = (int)ch;
          ch = (char)asciiNum;

Nie chcę jednak zagłębiać się maksymalnie w poszczególne etapy szyfrowania i odszyfrowania, a skupię się na samym specyficznym sposobie zapisu zaszyfrowanych znaków który sobie wymyśliłem i zakodziłem. ;)

Przykład 1:

Powiedzmy, że mam wyraz „Ola”, który zaszyfrowałem i chcę zapisać do pliku następnie odczytać i odszyfrować. Liczby powstałe w procesie szyfracji: 186220802, 16730814, 137205435. I tutaj pojawia się pytanie w jaki sposób mogę zapisać liczby tak aby osoba otwierająca plik nie domyśliła się, że poszczególne liczby reprezentują znaki? Jednym ze sposobów jest na przykład oddzielanie liczba przecinkami, kropkami lub innymi znakami interpunkcyjnymi. Mnie to jednak nie zadowalało wpadłem więc na pomysł, aby ustalić na stałe znaki „specjalne”, które zostaną zakodowane i „dodane” do powstałych liczb.

Przykład 2:

Ustalam, że moim znakiem specjalnym będzie przecinek następnie szyfruje jego kod i otrzymuję na przykład liczbę: 164916224.
Dodaje do każdej z wyżej powstałych liczb znak specjalny i do pliku wędruję taki oto ciąg liczb 18622080216491622416730814164916224137205435 :)

Jest jednak problem w sytuacji gdy ciąg znaków wygląda tak „O,l,a,,,”, a znakiem specjalnym jest przecinek. Odczytanie z pliku zaszyfrowanego ciągu z użyciem jako znak specjalny przecinka znacząco utrudnia odszyfrowanie – mamy długi ciąg liczb chcemy go podzielić po przecinku, ale tak naprawdę nie wiemy ile razy przecinek mógł wystąpić w danym wyrażeniu. By mieć możliwość swobodnego podziału tego typu ciągu liczb i odzyskać poszczególne liczby, aby je odkodować następnie odczytać oryginalny tekst źródłowy ustaliłem znaki specjalne spoza kodów Ascii. – Są to losowa przeze mnie wybrane trzy dziwne „krzaczki” które mi pięknie oddzielają poszczególne zakodowane znaki.

Klasę realizującą szyfrowanie i odszyfrowanie na podstawie obliczonych kluczy nazwałem Rsa. Jako, że spróbuję zmierzyć się z implementacją innych sposobów szyfrowania utworzyłem interfejs który w moim programie będzie reprezentował klasy szyfrujące i deszyfrujące.

Interfejs ICipher:

public interface ICipher
{
    StringCollection Encrypt(StringCollection sc);
    StringCollection Encrypt(string path);
    StringCollection Decrypt(StringCollection sc);
    StringCollection Decrypt(string path);
    void SaveToFile(string savePath);
}

Klasa Rsa:

/// <summary>
/// Klasa szyfrujaca RSA
/// </summary>
public class Rsa : ICipher
{
   #region Fields & Properties
   private BigInt _n;
   private BigInt _e;
   private BigInt _d;

   /// <summary>
   /// Tablica znakow specjalnych
   /// </summary>
   private readonly char[] _chars = { 'ฒ', 'ฑ', 'ฐ' };
   private StringCollection _scTemp;

   /// <summary>
   /// Zwraca tablice zawierajaca klucz prywatny i publiczny
   /// Indexy: 0 = n, 1 = e, 2 = d
   /// </summary>
   public BigInt[] Keys
   {
        get
        {
            return new BigInt[]
            {
                 _n,
                 _e,
                 _d
             };
         }
   }
   #endregion

   /// <summary>
   /// Konstruktor przyjmujacy wartosci umozliwiajace szyfrowanie
   /// </summary>
   /// <param name="n">n</param>
   /// <param name="e">e</param>
   /// <param name="d">d</param>
   public Rsa(BigInt n, BigInt e, BigInt d)
   {
            _n = n;
            _e = e;
            _d = d;
   }

    /// <summary>
    /// Konstruktor tworzacy obiekt Rsa tylko do odszyfrowywania danych
    /// Przyjmuje pare tworzaca klucz prywatny
   /// </summary>
   /// <param name="n">n</param>
   /// <param name="d">d</param>
   public Rsa(BigInt n, BigInt d)
   {
         _n = n;
         _d = d;
   }

   #region ICipher Members
   /// <summary>
   /// Szyfruje podana kolekcje stringow
   /// </summary>
   /// <param name="sc">Kolekcja stringow</param>
   /// <returns>Kolekcja zaszyfrowanych stringow</returns>
   public StringCollection Encrypt(StringCollection sc)
   {
       StringCollection cipheredText = new StringCollection();
       _scTemp = null;

       foreach (string s in sc)
       {
            //Zamiana stringa na tablice znakow
            char[] charArray = s.ToCharArray();

            int index = 0;
            string str = string.Empty;

            //Pobranie zakodowanych znakow specjalnych
            BigInt[] biArray = GetCipheredSpecialChar();

            foreach (char ch in charArray)
            {
                //Wylosowanie znaku specjalnego wykorzystanego do szyfracji
                index = Randomizer.UniqueInstance.Next(0, biArray.Count());

                //Szyfrowanie
                BigInt c = BigInt.Parse(ch.GetNumberOfChar().ToString());
                c = c.FastModuloPower(_e, _n);

                //Znak + znak specjalny
                str += c.ToString() + biArray[index].ToString();
            }

            cipheredText.Add(str);
       }
       _scTemp = cipheredText;

       return cipheredText;
   }

   /// <summary>
   /// Szyfruje wskazana zawartosc pliku
   /// </summary>
   /// <param name="path">Sciezka do pliku</param>
   /// <returns>Kolekcja zaszyfrowana</returns>
   public StringCollection Encrypt(string path)
   {
        StringCollection sc = null;
        _scTemp = null;

        try
        {
            string[] stringArray = File.ReadAllLines(path, Encoding.Default);
            sc = new StringCollection();
            sc.AddRange(stringArray);
            sc = Encrypt(sc);
        }
        catch (IOException)
        {
            throw;
        }
        catch (Exception)
        {
            throw;
        }

        return sc;
   }

   /// <summary>
   /// Deszyfracja z kolekcji stringow
   /// </summary>
   /// <param name="sc">Kolekcja stringow</param>
   /// <returns>Zwraca rozszyfrowany text</returns>
   public StringCollection Decrypt(StringCollection sc)
   {
        _scTemp = null;
        //Konwersja zakodowanych znakow specjalnych
        //i wrzucenie wszytkich do tablicy string
        string[] cipheredSpecialCharArray = GetCipheredSpecialChar().ToList()
                     .ConvertAll<string>((BigInt bi) =>
                {
                    return bi.ToString();
                }).ToArray();

        StringCollection decodedTextCollection = new StringCollection();

        foreach (string s in sc)
        {
             //Podział zakodowanych znakow metoda Split wedlug znakow specjalnych
             List<string> cStringArray = s.Split(cipheredSpecialCharArray, StringSplitOptions.RemoveEmptyEntries).ToList();

             string decodedText = string.Empty;
             //Iteracja po tablicy zawierajacej poszczegolne znaki w postaci zakodwanych liczb
             foreach (string str in cStringArray)
             {
                 BigInt de = BigInt.Parse(str).FastModuloPower(_d, _n);
                 char c = de.GetCharFromNumber();
                 decodedText += c;
             }
             //Dodanie do kolekcji utworzonej linii textu
             decodedTextCollection.Add(decodedText);
        }

        _scTemp = decodedTextCollection;

        return decodedTextCollection;
   }

   /// <summary>
   /// Deszyfruje text odczytany z pliku
   /// </summary>
   /// <param name="path">Sciezka do pliku</param>
   /// <returns>Zwraca rozszyfrowany text</returns>
   public StringCollection Decrypt(string path)
   {
        _scTemp = null;

        StringCollection sc = null;
        try
        {
             string[] stringArray = File.ReadAllLines(path, Encoding.Default);
             sc = new StringCollection();
             sc.AddRange(stringArray);
             sc = Decrypt(sc);
        }
        catch (IOException)
        {
              throw;
        }
        catch (Exception)
        {
              throw;
        }

        return sc;
   }

   /// <summary>
   /// Metoda realizujaca zapis do pliku
   /// </summary>
   /// <param name="savePath">Sciezka do zapisu</param>
   /// <param name="sc">Kolekcja do zapisu</param>
   public void SaveToFile(string savePath)
   {
         if (!String.IsNullOrEmpty(savePath) && _scTemp != null)
         {
              StreamWriter writer = null;
              try
              {
                  foreach (string s in _scTemp)
                  {
                      if (writer == null)
                      {
                          writer = new StreamWriter(savePath, false, Encoding.UTF8);
                      }

                      writer.WriteLine(s);
                 }
             }
             catch (IOException)
             {
                   throw;
             }
             catch (Exception)
             {
                  throw;
             }
             finally
             {
                  if (writer != null)
                  {
                       writer.Close();
                  }
             }
        }
   }
    #endregion

    #region Help Methods

    /// <summary>
    /// Metoda umozliwiajaca zapis kluczy do pliku
    /// </summary>
    /// <param name="savePath">Sciezka do zapisu</param>
    public void SaveKeysToFile(string savePath)
    {
         StreamWriter writer = null;
         try
         {
             writer = new StreamWriter(savePath, false, Encoding.UTF8);
             writer.WriteLine("Klucz publiczny:");
             writer.WriteLine("KP: (" + _e.ToString() + "; "
                           + _n.ToString() + ")");
             writer.WriteLine("Klucz prywatny:");
             writer.WriteLine("KPr: ( d=" + _d.ToString() + "; n="
                           + _n.ToString() + ")");
         }
         catch (IOException)
         {
              throw;
         }
         catch (Exception)
         {
              throw;
         }
         finally
         {
                if (writer != null)
                {
                    writer.Close();
                }
         }
    }

    /// <summary>
    /// Metoda pomocnicza szyfrujaca kody znakow specjalnych
    /// </summary>
    /// <returns>Tablica kodow znakow specjalnych</returns>
    private BigInt[] GetCipheredSpecialChar()
    {
         BigInt[] biArray = new BigInt[_chars.Length];
         for (int i = 0; i < _chars.Length; i++)
         {
             biArray[i] = BigInt.Parse(_chars[i].GetNumberOfChar()
                                 .ToString()).FastModuloPower(_e, _n);
         }

         return biArray;
    }
    #endregion
}

Moje spojrzenie na Code Camp

ccwawa09_140x140.jpg

Fragment „będę na” niestety mogę już zamienić na „byłem na”. Wszystko co dobre tak szybko się kończy, ale mam nadzieję, że za rok doznam powtórki w podobnym stylu.

Do Warszawy wyruszyłem dość wcześnie ponieważ miała to być moja dziewicza podróż zakamarkami stolicy obawiałem się, że mogę nieco błądzić i dlatego postanowiłem zapewnić sobie bufor czasowy. Po 2,5 godziny koszmarnej jazdy małym, ciasnym busikiem w pozycji embrionalnej około godziny 7 postawiłem swoją wielką stopę na Placu Defilad w centrum miasta. ;) Po 20 minutach błądzenia udało mi się odnaleźć odpowiedni przystanek i autobus którym bez przeszkód dotarłem pod samą siedzibę Microsoft – chyba byłem pierwszym oczekującym. :) – I tutaj podziękowania należą się organizatorom, którzy umieścili na stronie internetowej wydarzenia numery autobusów dojeżdżających na miejsce.

Zostałem przywitany przez bardzo miłą Panią, która zaprosiła mnie na skosztowanie przygotowanych specjalnie dla uczestników napojów (kawa, soczki, woda, mleko. :)) – Jestem przekonany, że tego dnia nikt spragniony, ani nawet diabelnie głodny stamtąd nie wyszedł (w połowie konferencji wchłanialiśmy pizze! :)).

„Programowanie równoległe i rozproszone „ – Pan Tomasz Kopacz

Zdecydowanie na ten temat było za mało czasu. Dużo informacji, moim zdaniem przekaz był jasny i zrozumiały. Dowiedzieliśmy się jakiego rodzaju narzędzia znajdują się w .NET 4.0 oraz jaki będzie kierunek dalszego rozwoju programowania równoległego.

Ogólną ocenę przyznaje 8/9

„Media w Silverlight – dostarczanie niezapomnianych wrażeń” – Panowie Piotr Czekała, Krzysztof Bartkowski

Generalnie o Silverlight nie mam zbyt wielkiego pojęcia. Wiem tylko, że to co zazwyczaj widzę w internecie i jest wykonane dzięki tej technologii wygląda w większości przypadków imponująco. Panowie zdecydowanie to potwierdzili. Bardzo fajny opis wykorzystywanych narzędzi i technologii – poparty faktycznie zapierającymi dech w piersiach przykładami. :) Jednak było coś co mi strasznie przeszkadzało podczas tej prelekcji – jeden z prowadzących ciągle trzymał rękę w kieszeni – odruch nerwowy który zdecydowanie powinien poprawić.

Ogólną ocenę przyznaję 7/9

„Wyjątki kontrolowane w C#” – Pan Bartłomiej Legiędź – Zwycięzca Speaker Idola – Łódź.

Ta sesja podobała mi się najbardziej. Jasno zwięźle i na temat. Nieoceniona dawka informacji w pigułce.
Projekt nad którym pracuję Pan Bartłomiej:
Exceptional Plugin
Książkę którą polecił podczas prelekcji i po którą myślę, że za jakiś czas sięgnę ;):
Framework Design Guidelines – Krzysztof Cwalina, Brad Abrams

Ogólną ocenę przyznaję 9/9 :)

„ Ile cukru w cukrze – IronPython i jego zastosowania” – Pan Michał Żyliński

Wprawdzie prowadzący nie przekonał mnie do IronPythona, ale dał dobry wstęp do programowania w tym języku. Pod koniec sesji przedstawił bardzo ciekawy program prowadzony przez Microsoft skierowany do niewielkich firm dzięki któremu mogą przyśpieszyć swój rozwój – Zachęcam do zapoznania się ze szczegółowymi informacjami na stronie internetowej: BizSpark

Ogólną ocenę przyznaję 7/9

„Designer + Programista = Produkt Problem + Pomysł = Aplikacja” – Pan Andrzej Piotrowski – Zwycięzca Speaker Idola – Warszawa

Po tej sesji kolega siedzący obok zapytał mnie jak to możliwe, że ten Pan wygrał speaker idola… Może tragedii nie było, ale najsłabsza sesja. Chwilami czułem jak by prowadzący, nie wiedział o czym mówi. Być może jak sam powiedział zaraz po sesji, był to jego zły dzień.

Ogólną ocenę przyznaję 5/9

Ogólnie całej konferencji przyznaję ocenę 8/9 :)

Pierwsza praca

Nadszedł czas kiedy obowiązki związane ze szkołą mogę odsunąć na dalszy plan. Zbliża się mój ostatni semestr studiów, a wraz z nim szereg przedmiotów którym nie będę musiał poświęcać stu procentowej uwagi. Postanowiłem, więc rozpocząć poszukiwania swojej pierwszej pracy i podzielić się tą nieodpartą chęcią właśnie tutaj. Należę do grona osób które podczas studiów skupiały się na nauce, rozwoju własnej osoby, w moim przypadku mogę jeszcze dodać setki godzin spędzonych w domu nad pogłębianiem umiejętności programistycznych (w końcu studia to tylko zarys wielu zagadnień itd.). Skoro prawie nie mam udokumentowanego doświadczenia (napisałem tutaj „prawie” ponieważ mam za sobą 1 miesiąc praktyki podczas której zajmowałem się implementacją niewielkiego programu raportującego, ale czy warto o tym wspominać w CV…) , a te które posiadam zostało zdobyte podczas trwających jeszcze studiów (czyli tzw.„doświadczenie akademickie„) to czym mam zachęcić pracodawcę, aby pozwolił mi się zmierzyć z rozmową wstępną na stanowisko programistyczne? Co może być moją rekomendacją? Te pytania dręczą mnie od dłuższego czasu.

Może?

  • setki godzin spędzonych nad rozwiązywaniem problemów implementacyjnych związanych
    z zadaniami szkolnymi, pojawiającymi się na forum codeguru.pl, csharp.pl
  • chęć wejścia na ścieżkę certyfikacyjną poprzez uczestnictwo w zajęciach „Study Group 70-536” organizowanych wspólnymi siłami wielu osób na mojej uczelni
  • CV – w którym zapewne jedyne co mogę zrobić to wymienić to z czym zetknąłem się podczas pracy nad własnym rozwojem
  • każdy wpis, każdy komentarz na tym blogu
  • wiele podziękowań od kolegów i koleżanek na mojej uczelni za pomoc w ciągłej ich walce z programowaniem
  • etc.

Jeśli odwiedzających ten oto blog (pracodawcy i nie tylko) taka rekomendacja przekonuje-zapraszam z przyjemnością zmierzę się z rozmową wstępną, z przyjemnością dam z siebie wszystko, bo jeśli już coś robię to wkładam w to maksimum energii.

Z poważaniem
Piotr Zarzycki

Dżemik z egzotycznych owoców – Abstract Factory :)

Zgodnie z zapowiedzią prezentuję własną interpretację jednego z zadań kończącego rozdział książki p.t. „C# 3.0 Design Patterns.”. Rozdział ten dotyczył wzorca projektowego „Abstract Factory”.

Delikatny zarys tego czym chcę się podzielić:

  • Krótko o tworzeniu własnych typów generycznych w C#
  • Zadanie, opis wzorca
  • Implementujemy, produkujemy (jemy i sprzedajem ;))

Typy generyczne:

W języku C# mamy możliwość tworzenia własnych typów generycznych.

class MyGenericType<T>
{
      private T _t;
}

Powyższa klasa daje możliwość zdefiniowania typu na jakim będzie mogła operować. Dodatkowo mamy możliwość nadawania ograniczeń na typy podawane podczas inicjalizacji obiektu.

 class MyGenericType<T> where T : IOperation, new()
{
        private T _t;
}

Ograniczenie to oznacza, że typ na którym będzie operowała klasa „MyGenericType” musi implementować interfejs IOperation, oraz jest zobowiazana posiadać jawnie zadeklarowany konstruktor.

Zadanie i opis wzorca:

Jeden z rozdziałów książki traktował o wzorcu projektowy „Factory Method” – przykład prezentujący działanie wzorca był opisem zdjęcia obrazującego źródło dostaw owoców awokado. Owoce te były dostarczane z różnych krajów Afryki. Zadanie kończące rozdział o wzorcu projektowym „Abstract Factory” odnosi się właśnie do tego zdjęcia – Należy wykorzystać „Abstract Factory” i opisać poniższą sytuację.

abstactfactory.png

Abstract Factory jest to wzorzec udostępniający instancje obiektów z istniejącej rodziny klas (Mam tutaj na myśli klasy dziedziczące po wspólnej klasie, wspólnym interfejsie). Obiekty te są odizolowane od klienta nimi zainteresowanego, co daje możliwość ich wymiany podmieniając tylko ich fabrykę. „Abstract Factory” to wzorzec który odpowiada za to co jest tworzone, a nie jak jest tworzone.

Implementujemy, produkujemy (jemy i sprzedajem ;))

Postanowiłem puścić wodzę fantazji i rozpocząłem budowę fabryki od zdefiniowania jej odpowiedzialności. Powstał genericsowy interfejs wraz z poniższymi ograniczeniami.

Interfejs „IAfricaFactory”:

interface IAfricaFactory<AfricaFruit>
        where AfricaFruit : IAfricaFruit, new()
{
     IInfoFruit GetNorthAfricaFruit();
     IInfoFruit GetSouthAfricaFruit();
     IOperationFruit GetROSA();
     IOperationFruit GetSudan();
}

Poszczególne metody będą zwracać instancję obiektów które implementują takie oto dwa interfejsy.

Interfejs „IInfoFruit”:

 interface IInfoFruit
 {
     string PriceFruit { get; }
     Quality QualityFruit { get; }
}

Interfejs „IOperationFruit”:

 interface IOperationFruit
 {
     string Marmalade();
     string OnSale();
}

Fabryka ma dostarczać i przetwarzać owoce nim jednak rozpocząłem ich tworzenie powstał interfejs zlecający im odpowiedzialność :)

Interfejs „IAfricaFruit”

interface IAfricaFruit
{
     string Price { get; }
     Quality QualityFruit { get; }
     string Marmelade();
     string OnSale();
}

Owoce:

Klasa „Avocado”:

class Avocado : IAfricaFruit
{
     #region IAfricaFruit Members
     public string Price
     {
        get
        {
            return "10 zl za kilogram";
        }
     }

     public Quality QualityFruit
     {
         get
         {
             return Quality.Druga;
         }
     }

     public string Marmelade()
     {
         return "Dżemik z avocado! :)";
     }

     public string OnSale()
     {
          return "Dżemik z owoców avocado sprzedajemy po: " + Price;
     }
     #endregion

     public override string ToString()
     {
          return "Avocado";
     }
}

Podobnie powstawały klasy „Banana” oraz „Lemon”. Następnie stworzyłem konkretną fabrykę(klasę) generyczną implementującą interfejs „IAfricaFactory”. Metody tworzą instancję klas implementujących intefejsy „IInfoFruit” oraz „IOperationFruit”.

Klasa „AfricaFactory”

class AfricaFactory<AfricaFruit> : IAfricaFactory<AfricaFruit>
        where AfricaFruit : IAfricaFruit, new()
{
     #region IAfricaFactory<AfricaFruit> Members
     public IInfoFruit GetNorthAfricaFruit()
     {
         return new NorthAfrica<AfricaFruit>();
     }

     public IInfoFruit GetSouthAfricaFruit()
     {
         return new SouthAfrica<AfricaFruit>();
     }

     public IOperationFruit GetROSA()
     {
         return new RepublicOfSouthAfrica<AfricaFruit>();
     }

     public IOperationFruit GetSudan()
     {
         return new Sudan<AfricaFruit>();
     }
     #endregion
}

Moja fabryka potrzebowała już tylko „kontaktu” z konkretnymi częściami bądź krajami Afryki. :)

Klasa „NorthAfrica”:

class NorthAfrica<AfricaFruit> : IInfoFruit
        where AfricaFruit : IAfricaFruit, new()
{
     private AfricaFruit _africaFruit;

     public NorthAfrica()
     {
           _africaFruit = new AfricaFruit();
     }
     #region IInfoFruit Members
     public string PriceFruit
     {
          get
          {
               return _africaFruit.Price;
          }
     }

     public Quality QualityFruit
     {
          get
          {
               return _africaFruit.QualityFruit;
          }
     }
     #endregion
}

Klasa implementuje interfejs „IInfoFruit”. Właściwości spełniające wymagania interfejsu „sięgają” do obiektu którego typ zostanie określony podczas tworzenia egzemplarza tej oto klasy, jednak jest pewne, że dostarczony typ musi implementować interfej „IAfricaFruit” oraz musi zawierać zadeklarowany jawnie konstruktor. Obiek dostarczanego typu tworzę w konstruktorze klasy „NorthAfrica”

Klasa „RepublicOfSouthAfrica”:

class RepublicOfSouthAfrica<AfricaFruit> : IOperationFruit
        where AfricaFruit : IAfricaFruit, new()
{
     private AfricaFruit _africaFruit;

     public RepublicOfSouthAfrica()
     {
          _africaFruit = new AfricaFruit();
     }

     public string Marmalade()
     {
          return _africaFruit.Marmelade();
     }

     public string OnSale()
     {
            return _africaFruit.OnSale();
     }
}

Klasa implementuje interfejs „IOperationFruit”. Tak samo jak w klasie „NorthAfrica” sięgam do zwartości typu który zostanie dostarczony podczas tworzenia egzemplarza klasy. Podobnie powstały klasy „SouthAfrica” (implementuje interfejs „IInfoFruit”) oraz „Sudan” (implementuje interfejs „IOperationFruit”). Mam już wszystko czego potrzebuję. Pozostaję tylko sprzedawać i jeść pyszny dżemik z owoców afrykańskich. ;)

Wywołanie:

//Fabryka Avocado
IAfricaFactory<Avocado> factoryOfBanana = new AfricaFactory<Avocado>();
//Dostarczam instancje obiektu "NorthAfrica"

IInfoFruit northAfrica = factoryOfBanana.GetNorthAfricaFruit();
//Wykorzystuje dostępne wlasciwosci
//aby sprawdzic cene i jakosc owocow

Console.WriteLine(northAfrica.PriceFruit);
Console.WriteLine("Jakość owoców: {0}", northAfrica.QualityFruit);
 //20zl za kilogram
//Jakosc owocow: Pierwsza

IOperationFruit RPA = factoryOfBanana.GetROSA();
//Po ile sprzedajemy :)
string p = RPA.OnSale();
Console.WriteLine(RPA.OnSale());
//Dżemik!!
string d = RPA.Marmalade();
Console.WriteLine(RPA.Marmalade());

//Dzemik z owocow avocado sprzedajemy po: 10 zl za kilogram
 //Dzemik z avocado! :)

Do fabryki możemy dostarczać kolejne owoce (klasy). Ważne jest aby każdy dostarczony typ do utworzonej przy użyciu typów generycznych fabryki implementował interfejs IAfricaFruit. :) Miłego analizowania. ;)

Konwersja liczb binarny => dziesiętny i nauka po fakcie. ;)

W swoim projekcie z algorytmów genetycznych potrzebowałem przekonwertować liczbę zapisaną w systemie binarnym na system dziesiętny.
Liczba ta była przechowywana w tablicy typu int.

Utworzyłem taką oto funkcję konwertującą liczby z systemu binarnego na dziesiętny „na piechotę” ;):

public int ConvertFromBinaryToInt(int[] binaryNum)
{
    //Wykladnik potegi
    int power = 0;
    //Aktualna wartosci
    int value = 0;
    //Czytam zawartosc tablicy od konca
    for (int i = binaryNum.Length - 1; i >= 0; i--)
    {
         //Jesli napotkam w tablicy 1
         if (binaryNum[i] == 1)
         {
             //value + 2^power
             value += (int)Math.Pow(2, power);
         }
         power++;
     }

     return value;
}

Zorientowałem się jednak po napisaniu powyższej metody że można to osiągnąć w trywialny sposób:

public int ConvertFromBinaryToInt(int[] binaryNum)
{
  object[] objArray = new object[binaryNum.Length];
  binaryNum.CopyTo(objArray, 0);
  //lacze zawartosc tablicy
  //object[] w jeden string
  string str = String.Concat(objArray);

 //Konwersja na system
 //dziesietny z dwojkowego
  return Convert.ToInt32(str, 2);
}

Chyba każdemu zdarzyło się napisać coś, a dopiero później dojść do wniosku, że można było to osiągnąć w dużo prostszy sposób. ;)