Spotkanie inauguracyjne 2011

Zapraszam na pierwsze, inauguracyjne spotkanie grupy w nowym semestrze, które odbędzie się w czwartek (13.10.2011) o godzinie 18:15 w sali D09.

 

Tagi:

Nie śpij – programuj!

 

Jesteś zapalonym programistą i chętnie podejmujesz nowe wyzwania? Nie może Cię zabraknąć na eliminacjach do 24-godzinnego maratonu programistycznego! Razem z przyjaciółmi stwórz trzyosobowy team i przekonaj się, jak wiele można zrobić w krótkim czasie, gdy pracuje się razem.

Ogólnopolskie zawody programistyczne Deadline24 to prawdziwy test wytrzymałości, kreatywnego myślenia i interdyscyplinarnej wiedzy. Po przejściu eliminacji, najlepsze drużyny zostaną zaproszone na finał do Gliwic, gdzie czekać je będzie 24-godzinny programistyczny maraton.  Zawodnicy, odcięci od zewnętrznego świata, będą rywalizować między sobą, pisząc nietypowy program. O wygranej zadecyduje jakość wykonanej w tak krótkim czasie pracy. Uczestnicy mogą uzbroić się w dowolny sprzęt i oprogramowanie. Organizatorzy zapewniają każdej drużynie jedno gniazdko 230V i dostęp do wirtualnej areny - serwera konkursowego. Liczy się inwencja i praca zespołowa. W pierwszej edycji konkursu zadaniem informatyków była tresura żukoskoczków - musieli opanować motywowanie, ruch, a nawet rozmnażanie tych stworzonek, by uratować świat przed zagładą i negatywną energią. Tegoroczne zadanie będzie z pewnością nie mniej ekscentryczne.

Udział w zawodach jest bezpłatny. Zarówno w eliminacjach jak i w finale uczestnicy pracują na swoim sprzęcie, mając pełną swobodę wyboru systemu operacyjnego, środowiska i języka programowania. Eliminacje trwają 5 godzin, odbywają się zdalnie. Drużyny otrzymują zadania i dane wejściowe do zadań. Celem jest wygenerowanie (w dowolny sposób) odpowiedzi i przesłanie ich na serwer sprawdzający w wyznaczonym czasie. Finał trwa 24 godziny, odbywa się na Politechnice Śląskiej w Gliwicach. Uczestnicy mogą korzystać ze wszelkich materiałów przyniesionych ze sobą, lecz dostęp do pomocy zewnętrznej jest zabroniony. Zadanie będzie miało charakter interaktywny, komunikacja z serwerem konkursowym będzie się odbywała za pomocą TCP/IP.

Pomysł na organizację Deadline24 zrodził się na początku 2009 roku. Są to pierwsze tego typu zawody w Polsce. Organizatorami konkursu są: firma Future Processing i Politechnika Śląska. Strona www z poprzedniej edycji wraz z regulaminem, galerią, wynikami i zadaniem konkursowym jest dostępna pod adresem http://www.deadline24.pl.

Filozofią konkursu jest przyciągnięcie do udziału pasjonatów programowania, oryginalnych, kreatywnych i kompetentnych osób. Konkurs wyłoni młodych programistów o nieprzeciętnych umiejętnościach, indywidualistów w akademickim świecie IT, utalentowanych ludzi z branży. Konkurs ma niestandardową formułę. Promuje ludzi o wyjątkowych zdolnościach programistycznych, działających w nietypowych dla siebie warunkach.

Nagrody dla zwycięzców będą równie niezwykłe, jak programistyczne zadanie, z którym się zmierzą. Dobra zabawa gwarantowana! Eliminacje już 26 marca. Wejdź na stronę konkursu http://www.deadline24.pl, zapoznaj się z regulaminem i aplikuj! Drużyny, które pomyślnie przejdą pierwszy etap, wezmą udział w maratonie programistycznym. Konkurs rozpocznie się w Gliwicach 26 kwietnia i potrwa całą dobę.

 

Tagi: ,

Windows Phone 7

Tydzień temu (oraz jakiś czas temu) miałem przyjemność co nie co opowiedzieć o nowym systemie na urządzenia mobilne Microsoftu – Windows Phone 7. Ba nawet udało się wypożyczyć jeden telefon z Microsoftu – LG GW910, który widać na rysunku poniżej:

image

Przy okazji pożyczenia korzystam sobie z niego od dwóch tygodni i muszę przyznać, że nowy system i sam telefon spisuje się bardzo dobrze, jestem pozytywnie zaskoczony działanie. Nie sądziłem, że system na telefonie może tak szybko działa, przy tym tak stabilnie (jak na razie nie miałem żadnych problemów). No ale nie ma co się dziwić, jednak pod maską siedzi mały potwór jak na urządzenia mobilne (ostatnio dla wujka oddałem swój stary komputer, aby mógł sobie korzystać z Internetu, który ma parametry zbliżone do parametrów tego telefonu Open-mouthed smile ).

No dobra ale wracając do mojej prezentacji (a dokładnie dwóch Smile ). Ogólnie była podzielona na trzy części.

Podczas pierwszej opowiedziałem o samym telefonie i systemie, co pojawiło się nowego i dlaczego. Nie będę tutaj tego wszystkiego opisywał szczególnie, że w innych miejscach w Internecie można znaleźć opisy ale wspomnę o jednej rzeczy. Osobiście bardzo podoba mi się nowy interfejs użytkownika (tak zwane Metro wzorowane na istniejących metrach – kolejkach podziemnych Smile ) zaproponowany przez Microsoft. Pamiętam kiedyś (bodajże na prezentacji z MIXa, gdzie po raz pierwszy został pokazany Windows Phone 7) jak na filmie widziałem nowy interfejs miałem co do niego mieszane uczucia, czy będzie fajny. Ale wystarczyło trochę poużywać nowy interfejs i bardzo przypadł mi do gustu. Bardzo szybko można się odnaleźć w nim i po chwili z nim bez problemów pracować.

Przy interfejsie też widać, że jednak Microsoft sporo czasu poświęcił na myślenie (nie wiem, czy gdzieś indziej ktoś na to wpadł, więc mogę się myli) ale zastanawialiście się, czemu domyślny interfejs Windows Phone 7 jest czarny? Okazuje się, że nie bez powodu. W telefonach z Windows Phone 7 wykorzystywane są wyświetlacze OLED, które jak “świecą” na czarno zużywają dużo mniej energii niż świecąc na jasno. W materiałach o Windows Phone 7 podaje się, że gdy właśnie ekran OLED “świeci” na czarno to zużywa połowę mniej energii niż identyczny ekran LCD, czyli jak widać znacznie mniej. Natomiast w przypadku świecenia jasno, tutaj ekrany OLED wypadają dużo gorzej niż ekran LCD – zużywa “tylko” trzy razy więcej energii niż ekran LCD. Więc widać to, że interfejs domyślnie jest ciemny to nie tylko widzi misie kogoś tam ale zamierzony cel, dzięki któremu telefon może działać dłużej na baterii.

Kolejną częścią prezentacji był Marketplace ale nie od strony zwykłego użytkownika ale od strony potencjalnego twórcy oprogramowania. Tutaj wspomnę tylko o dwóch rzeczach. Po pierwsze warto pisać aplikacje na Windows Phone 7, teraz jest ich bardzo mało w porównaniu np. z innymi systemami. Nie na ile w tej chwili te dane są aktualne ale z tego co się orientuje to w marketplace dla Windows Phone 7 aplikacji jest około 1500 tysiąca, natomiast w przypadku Androida jakiś czas temu widziałem informacje, że pękła liczba 100 tysięcy, czyli jak widać jest co nadgonić i co fajne od razu wrzucając aplikację do marketplace dystrybuowana jest ona globalnie.

Dodatkowo studenci aplikacje mogą wrzucać za darmo wystarczy mieć tylko konto w Dreamsparku, a takie konto może mieć każdy student. Niestety na razie tak różowo nie jest i jakimś cudem polscy studenci z tego nie mogą korzystać. Ale z tego co wiem to polski odział Microsoft pracuje nad tym, aby jednak dać możliwość studentom z Polski wrzucania aplikacji za darmo do marketplace. Jak coś więcej będę wiedział to na pewno dam znać Smile

Ostatnią częścią prezentacji był już sam Silverlight dla Windows Phone 7. Pokazałem kilka prostych dem, jak korzystać z tego co daje nam telefon i jak łatwo niektóre z nich osiągnąć. Nie będę tutaj opisywał dem (ale planuje to zrobić za jakiś czas na swoim blogu – http://plawgo.pl). Jak ktoś byłby zainteresowany już teraz jak pisać aplikacje to mogę polecić dwa miejsca w sieci:

Dla wszystkich, którzy chcą tworzyć aplikacje dla Windows Phone 7 życzę powodzenia!!!

Tagi:

Hasło - aplikacja MVVM

Na prezentacji pokazałem sposób tworzenia aplikacji WPF z wykorzystaniem Visual Studio, Blend i wzorca projektowego MVVM. Kod i slajdy będą na SkyDrive grupy. Dzisiaj chcę wam pokazać jak można wykonać podobną aplikacje która może nam posłużyć do „wymyślania” haseł na konta ;p
To do dzieła.
1 Tworzymy nowy projekt.
Nowy projekt utworzymy z wykorzystaniem Blenda. Jeżeli ktoś nie ma Blenda może śmiało to samo wykonać w Visual Studio. Uruchamiamy Blenda po czym w okienku które nam wyskoczyło naciskamy New Project. Alternatywnie możemy zrobić to samo przez File-> New Project. Wybieramy typ projektu jako WPF Application. Nazywamy nasz projekt Haslo, zapamiętujemy gdzie go zapisujemy i klikamy OK.
2 Projektujemy widok
Powinno ukazać się nam okno domyślnie utworzone przez Blenda. Będziemy dążyć aby wygląd naszej aplikacji był taki jak niżej.
Tworzyć nasz widok możemy na dwa sposoby, poprzez przeciąganie kontrolek(niektórzy mogą preferować ten sposób) lub przez deklaracje bezpośrednio w kodzie. Ja osobiście wolę ta druga metodę wiec jej będziemy używać. Aby zobaczyć nasz kod klikamy na View-> Active Document View-> Split View ( będziemy widzieć kod i wygląd naszej aplikacji ).  Zabieramy się za tworzenie widoku.  Zaczynamy od zdefiniowania w naszym Gridzie dwóch wierszy do których będziemy przypisywać kontrolki. Uzyskujemy to przez następujący kod:
<Grid.RowDefinitions>
           <RowDefinition Height="Auto"/>
           <RowDefinition Height="auto"/>
</Grid.RowDefinitions>
 Następnie dodajemy dwa StackPanele. Jeden przypisujemy do pierwszego wiersza, drugi do drugiego.
W pierwszym tworzymy Labela który będzie nam wyświetlać losowane liczby. Wielkość czcionki ustawiamy na 40, wyśrodkowujemy w pionie i poziomie. Jego zawartość(Content) musimy połączyć z właściwością ViewModel który będziemy tworzyć w dalszej części. Drugi StackPanel będzie troche bardziej złożony.  W jego wnętrzu deklarujemy dwa kolejne StackPanele. W obu ustawiamy orientację na poziomą i wyrównujemy w poziomie na środek. Do tej pory nasz fragment powinien wyglądać następująco.

 <StackPanel Grid.Row="0">
      <Label Content="{Binding Path=Liczby,UpdateSourceTrigger=PropertyChanged}" FontSize="40" HorizontalContentAlignment="Center"
                  VerticalContentAlignment
="Center"/>
      </StackPanel>
      <StackPanel Grid.Row="1">
      <StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
            <Button Command="{Binding Start}" Height="45" Content="Start" FontSize="25" Margin="0,0,10,0"/>
            <Button Command="{Binding Stop}" Height="45" Content="Stop" FontSize="25" Margin="0,0,10,0"/>
      </StackPanel>
      <StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
            <Slider Value="{Binding Slider}" Width="200" Height="20" Margin="0,10,0,0" />
            <Label Content="{Binding Path=SliderValue, UpdateSourceTrigger=PropertyChanged}" FontSize="18"/>
      </StackPanel>
</StackPanel>

Postępujemy analogicznie jak w przypadku pierwszego. Wypełniamy drugi następującym kodem:
<StackPanel Grid.Row="1">
       <StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
               <Button Command="{Binding Start}" Height="45" Content="Start" FontSize="25" Margin="0,0,10,0"/>
               <Button Command="{Binding Stop}" Height="45" Content="Stop" FontSize="25" Margin="0,0,10,0"/>
        </StackPanel>
        <StackPanel  HorizontalAlignment="Center" Orientation="Horizontal">
                <Slider Value="{Binding Slider}" Width="200" Height="20" Margin="0,10,0,0" />
                <Label Content="{Binding Path=SliderValue, UpdateSourceTrigger=PropertyChanged}" FontSize="18"/>
         </StackPanel>
 </StackPanel> 
 Przy przyciskach pojawila się nowa właściwość – Command.
 Nasz widok powinien być już gotowy. Później będziemy musieli na chwile do niego wrócić alby połaczyć nasz ViewModel z przed chwila utworzonym widokiem. Budujemy nasz projekt (Ctrl+Shift+B)
 
3 Visual Studio
W tej części zajmiemy się logika naszej aplikacji. Otwieramy w Visual Studio projekt który wczesniej utworzyliśmy.  Na początku zajmiemy się utworzeniem naszego ViewModelu później przystąpimy do klas które będą mu potrzebne. Tworzymy nowa klasę :
 
Nazywamy ją MainViewModel i zatwierdzamy.  Nowo utworzona klasa musi implementować interfejs INotifyPropertyChanged. Do tego potrzebne będzie nam dodanie przestrzeni nazw (using System.ComponentModel) . Aby przyśpieszyć sobie prace Visual Studio zaimplementuje go za nas. Klikamy prawym przyciskiem myszki na przed chwila zadeklarowanej implementacji, wybieramy Implement Interface -> Implement Interface.
 
 Dodajemy metodę która będzie wywoływana przy każdej zmianie jakiejkolwiek właściwości. Będzie nam to potrzebne aby nasz widok mógł się zorientować, że zmiana miała miejsce i należy jego dane zaktualizować.
public void PropertyChangedInvoker(string name)
{
    if (PropertyChanged != null)
    {
         PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
}

Teraz kolej nadeszła na utworzenie właściwości w naszej klasie, dodajemy następujący kod:

//wartosc suwaka w postaci double
private double _slider;
public double Slider
{
     get { return _slider; }
     set
     {
          _slider = value;
          SliderValue = Convert.ToInt32(_slider);
     }
}

//pozycja suwaka w postaci int
private int _sliderValue;
public int SliderValue
{
     get { return _sliderValue; }
     set
     {
          _sliderValue = value;
          PropertyChangedInvoker("SliderValue");
     }
}

//liczby które są wyświetlane w widoku
private string _liczby;
public string Liczby
{
     get { return _liczby; }
     set
     {
          _liczby = value;
          PropertyChangedInvoker("Liczby");
     }
}

//odpowiada za trzymanie informacji czy przcisk Stop został nacisniety
private bool _stopButtonClicked;
public bool StopButtonClicked
{
     get { return _stopButtonClicked; }
     set
     {
          _stopButtonClicked = value;
          PropertyChangedInvoker("StopButtonClicked");
     }
}

//odowiada za trzymanie informacji czy przycisk Stop jest aktywny
private bool _canStopButtonExecute;
public bool CanStopButtonExecute
{
     get { return _canStopButtonExecute; }
     set
     {
          _canStopButtonExecute = value;
          PropertyChangedInvoker("CanStopButtonExecute");
     }
}

Naszemu ViewModelowi dalej czegoś brakuje. W Widoku utworzyliśmy 2 przyciski. Teraz pokaże co zrobić żeby je trochę ożywić. Pierwszym zadaniem będzie utworzenie i klas które będą implementowały interface ICommand. Klasy będą nazywać się odpowiednio StartCommand i StopCommand. Sama implementacja wygląda dokładnie tak samo jak wcześniej pokazałem. Wcześniej jednak do każdej z nich musimy dodać następującą przestrzeń nazw - using System.Windows.Input; Po tym nasze klasy, w tym wypadku StartCommnad, powinny wyglądać tak:

class
StartCommand : ICommand
{
    public bool CanExecute(object parameter)
    {
        throw new NotImplementedException();
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        throw new NotImplementedException();
    }
}

Klasa posiada dwie metody i jeden event. Pierwsza metoda(CanExecute) jest wywoływana gdy event (CanExecuteChanged) zostanie „wzniesiony”. Tak nasz widok sprawdza czy dana komenda może być wykonana.
Druga metoda (Execute) zawiera kod który będzie wywołany w przypadku gdy komenda ma zostać wykonana ( w naszym przypadku przez naciśniecie przycisku).
Musimy trochę rozbudować nasze klasy gdyż puste metody niewiele nam pomogą J. Pierwszym krokiem będzie utworzenie konstruktora i dodanie referencji do naszego ViewModelu dla naszych klas. Pozwoli nam to odwoływać się do jego właściwości.
private readonly MainViewModel _vm;
public StartCommand(MainViewModel viewModel)
{
    _vm = viewModel;
}
Dodamy teraz trochę logiki do naszych metod. Rozbudujemy tez nasz event.

public bool CanExecute(object parameter)
{
    return _vm.CanStopButtonExecute == false && _vm.SliderValue != 10 && _vm.SliderValue != 0;
}

public
event EventHandler CanExecuteChanged
{
    add { CommandManager.RequerySuggested += value; }
    remove { CommandManager.RequerySuggested -= value; }
}

public
void Execute(object parameter)
{
    _vm.CanStopButtonExecute = true;
    System.Threading.ThreadPool.QueueUserWorkItem(_vm.Losowanie);
}
Wytłumaczenia wymagają dwie rzeczy. Pierwsza to co to jest losowanie. Losowanie to będzie metoda która będziemy jeszcze implementować w ViewModelu. Będzie ona odpowiedzialna za losowanie liczb. Drugą rzeczą dla niektórych może być tajemnicze wywołanie metody -System.Threading.ThreadPool.QueueUserWorkItem. Pozwala nam ono wykonać dana metodę w osobnym wątku które będzie „obliczać” swoje rzeczy niezależnie od głównego wątku naszej aplikacji. Więcej informacji znajdziecie we wcześniejszych wpisach z tamtego roku. Dlaczego tak ? Nie chcemy aby nad naszą aplikacja pojawiła się klepsydra :P Nie odpowiadałaby ona na nasze żądania.Teraz do rzeczy bo zostało nam trochę roboty jeszcze. Druga nasza klasa powinna wyglądać podobnie:

class
StopCommand : ICommand
{
    private readonly MainViewModel _vm;
    public StopCommand(MainViewModel viewModel)
    {
         _vm = viewModel;
    }

    public bool CanExecute(object parameter)
    {
         return _vm.CanStopButtonExecute;
    }

   
public event EventHandler CanExecuteChanged
    {
         add { CommandManager.RequerySuggested += value; }
         remove { CommandManager.RequerySuggested -= value; }
    }

   
public void Execute(object parameter)
    {
         _vm.StopButtonClicked = true;
    }
}

Musimy teraz „podpiąć” dopiero co stworzone klasy do ViewModelu. Przechodzimy do niego i  tworzymy kolejne dwie właściwości i w konstruktorze przypisujemy do nich nowe obiekty:

public
ICommand Start { get; set; }
public ICommand Stop { get; set; }
public MainViewModel()
{
     Start = new StartCommand(this);
     Stop = new StopCommand(this);
}

Dokładnie do tych dwóch właściwości bindowaliśmy nasze przyciski poprzez Command.
Kolejnym krokiem ( obiecuje ze już nie wiele tego zostało ) jest utworzenie klasy która będzie nam losować liczby o danej długości jak i metoda o której wcześniej wspomniałem. Zaczniemy od klasy.
Tworzymy i nazywamy ja Losomat. Oto logika która jest w niej zawarta:

public static class Losomat
{
    private const int max = 999999999;
    private const int min = 100000000;
    private static readonly Random Random = new Random();

   
public static string Losuj(int ilosc)
    {
       return
       Random.Next(Convert.ToInt32(min / Math.Pow(10, 9 - ilosc)), Convert.ToInt32(max / Math.Pow(10, 9 - ilosc))).ToString();
    }
}

Mam nadzieje że wszytko w niej jest jasne.
Weźmiemy się teraz za metodę. Przechodzimy do ViewModelu i dodajemy.

public
void Losowanie(object param)
{
    for (int i = 0; i < SliderValue; i++)
    {
        Liczby += "0";
    }
    for (int i = SliderValue; i > 0; i--)
    {
        while (!StopButtonClicked)
        {
            var temp = Losomat.Losuj(i);
            Liczby = Liczby.Substring(0, SliderValue - i) + temp;
            System.Threading.Thread.Sleep(10);
        }
        StopButtonClicked = false;
     }
     CanStopButtonExecute = false;
}

Rzeczą która może się przydać z tego kawałka kodu może być System.Threading.Thread.Sleep. Jest to metoda która usypia dany watek na podana ilość czasu. Czas podajemy w milisekundach.
Ostatnia rzeczą jaka musimy wykonać jest złączenie Widoku z ViewModelem. Przechodzimy do Widoku, przed Gridem dodajemy przestrzeń nazw i definiujemy zasób dla naszego okna.

xmlns:Haslo="clr-namespace:Haslo"
<Window.Resources>
     <Haslo:MainViewModel x:Key="ViewModel"/>
</Window.Resources>

 Łączymy nasz nowy zasób z Gridem poprzez DataContext:

<Grid x:Name="LayoutRoot" DataContext="{StaticResource ViewModel }" >

W ostateczność nasz początek kodu Widoku powinien wyglądać następująco :
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Haslo="clr-namespace:Haslo"
    x:Class="Haslo.MainWindow"
    x:Name="Window"
    Title="Haslo"
    Width="459" Height="204">    
    <Window.Resources>
           <Haslo:MainViewModel x:Key="ViewModel"/>
   </Window.Resources>
<Grid x:Name="LayoutRoot" DataContext="{StaticResource ViewModel }" >
Po tych wszystkich bojach możemy przystąpić do kompilacji naszego programu i cieszyć się jego możliwościami :D Kod z komentarzami będzie można pobrać z linku niżej.

Tagi: , ,

Express App Framework - wstęp

Ostatnio w ramach grupy .NET, miałem okazję na prezentacji, opowiedzieć Wam o XAF-ie. Po prezentacji wpadłem na pomysł żeby założyć bloga, i opisać ten Framework. Dlatego też, nie będę umieszczał materiałów które prezentowałem, a w zamian w ramach autopromocji zapraszam Was na http://dawidtulski.net :) Tam w cyklu wpisów, znajdziecie na pewno to co już pokazywałem oraz wiele innych (mam nadzieje ciekawych) rzeczy dotyczących XAF-a.

Tagi: ,

Ustalenia po spotkaniach organizacyjnych

Hej :)

W ubiegłym tygodniu odbyły się dwa, organizacyjne, spotkania grupy. Postanowiliśmy, że tak, jak w latach poprzednich, będą dwa typy spotkań: Warsztaty oraz Prezentacje. Na warsztatach, w tym semestrze będziemy uczyli się C# oraz pisali małe projekty. Spotkania zawsze będą odbywały się we wtorki (prezentacje) o godzinie 17.30 oraz w czwartki (warsztaty) o godzinie 19.

Zapraszam również na jutrzejsze spotkanie (wtorek 26.10), na którym Mateusz Jaskółowski opowie o tworzeniu aplikacji w WPF z użyciem wzorca MVVM. Opowie również o narzędziu do tworzenia wyglądu naszej aplikacji WPF. Zapraszamy!

Nie zapomnijcie zarejestrować się na: https://codeguru.pl/group-82/LectureDetails/1,4686.aspx

 

Tagi: , , ,

Pierwsze, powakacyjne spotkanie

 
  Witam Was w nowym roku akademickim!
Czas zacząć spotkania naszej grupy :) Już niebawem, bo we wtorek 19 października o godzinie 18.00 w sali 49 na Wydziale Matematyki i Informatyki odbędzie się pierwsze powakacyjne spotkanie. Będzie to spotkanie organizacyjne, na którym chcemy ustalić jak będą wyglądały spotkania w tym roku, co chcielibyście robić na warsztatach, prezentacje na jaki temat chcielibyście usłyszeć itp.Będzie też trochę o nowych zasadach premiowania aktywnych uczestników i wiele więcej.
Gorąco zapraszamy.

P.S Przypominam o rejestracji na spotkanie: https://codeguru.pl/group-82/LectureDetails/1,4622.aspx

Tagi: , , ,

Eastgroup.pl na facebooku