Monthly archive for June, 2008

Kontenery haszujące w Visual C++

2008-06-11 21:10

W standardowej bibliotece pojemników (STL) języka C++ jest póki co poważny brak. Nie ma mianowicie kontenerów opierających się na mechanizmie haszowania (hashing), znanego też pod mniej jednoznaczną nazwą mieszania. Mówiąc zupełnie najprościej, takie pojemniki są pewnym uogólnieniem zwykłych tablic, które nie są jednak indeksowane liczbami całkowitymi, a kluczami dowolnego typu. Klucze te są jednak wpierw przepuszczane przez pewną funkcję (funkcję haszującą) i dopiero wynik używany jest do znalezienia wartości, z którą ów klucz jest związany. Istnieje też kilka metod rozwiązywania problemu kolizji, gdy kilka kluczy zostanie odwzorowanych na to samo miejsce w tablicy.
Zaletą haszowania jest szybkość: średnio dostęp do wartości związanej z danym kluczem jest wykonywanym w czasie stałym. Tak, stałym, czyli O(1). Jakkolwiek można być pesymistą i przewidywać, że przy odpowiednio złośliwym doborze kluczy czas ten urośnie do liniowego (O(n), ale w praktyce tablice haszujące zachowują się świetnie. No a to jest przecież najważniejsze :)

W STL nie ma jednak kontenerów używających haszowania. Mimo to wiele kompilatorów oferuje je we własnym zakresie. I tak nasz ulubiony Visual C++ udostępnia dwa “półstandardowe” nagłówki: hash_set i hash_map. Zawierają one klasy (multi)map oraz (multi)zbiorów, z wierzchu wyglądających właściwie identycznie jak zwykłe mapy i zbiory (std::map i std::set) z STL. Klasy te nazywają się hash_set, hash_map, itp., i celem zachowania zgodności ze standardem C++ umieszczone są nie w przestrzeni std, lecz stdext.

O istnieniu tych klas warto pamiętać, gdy tworzymy kod kluczowy pod względem wydajności. W programowaniu gier często są to na przykład przeróżne menedżery zasobów, które odwzorowują pewne identyfikatory (np. łańcuchy znaków) na obiekty w rodzaju modeli, tekstur, próbek dźwiękowych, itd. Szybkość działania przechowujących je pojemników może być ważna i warto poszukać alternatyw dla standardowej klasy map (która przecież teoretycznie “wyciąga” tylko O(logn) dla wyszukiwania). Jeśli przy okazji martwimy się przenośnością na inne kompilatory niż VC++ lub zgodnością ze standardem, to możemy spróbować przełączania między zwykłymi a haszującymi pojemnikami, np. tak:

  1. #if defined(_MSC_VER) && !defined(STANDARD_COMPLIANCE)
  2.     typedef stdext::hash_map<std::string, Object*> ResourceManagerMap;
  3. #else
  4.     typedef std::map<std::string, Object*> ResourceManagerMap;
  5. #endif

Naturalnie ‘kod niezależny od kontenera’ to dość często utopia, ale przy korzystaniu tylko z prostych operacji typu wstawianie-usuwanie-wyszukiwanie nie powinniśmy napotkać większych problemów.

Tags: , , ,
Author: Xion, posted under Uncategorized » 3 comments

Triki z PowerShellem #4 – DirectX

2008-06-10 11:13

Jakiś czas temu pokazałem, że w PowerShellu można zrobić rzeczy, które są – jak na konsolkę tekstową – co najmniej niespotykane. Przedstawiłem na przykład sposób na wyświetlenie zwykłego windowsowego okienka. Nie było ono aczkolwiek zbyt interesujące, jako że w środku było zupełnie puste – chociaż, oczywiście, Aero robił co mógł, by wyglądało ono na atrakcyjniejsze niż było w rzeczywistości ;)
Jako że zajmowania się rzeczami zupełnie nieprzydatnymi nigdy dość, postanowiłem więc pewnego razu spróbować wnieść w stworzoną formę nieco więcej życia. Efekty okazały się raczej ciekawe, przedstawiając się następująco:

DirectX w PowerShellu - trójkąt (screen 1) DirectX w PowerShellu - trójkąt (screen 2) DirectX w PowerShellu - trójkąt (screen 3)

Tak, to jest trójkąt. Tak, on się obraca. Tak, na pasku tytułowym okna jest napisane Direct3D… Wszystkie te trzy fakty nie są żadnym zbiegiem okoliczności :) Za wszystko odpowiedzialny jest ten ono skrypt:

  1. # D3D.ps1 - próba użycia Direct3D w PowerShellu
  2.  
  3. # Ładujemy assemblies
  4. [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
  5. [Reflection.Assembly]::LoadWithPartialName("System.Drawing") | Out-Null
  6. [Reflection.Assembly]::LoadWithPartialName("Microsoft.DirectX") | Out-Null
  7. [Reflection.Assembly]::LoadWithPartialName("Microsoft.DirectX.Direct3D") | Out-Null
  8.  
  9. # Tworzymy okienko
  10. $form = New-Object Windows.Forms.Form
  11. $form.ControlBox = $false # Bo zamykanie niespecjalnie działa :P
  12. $form.Text = "Direct3D"
  13.  
  14. # Tworzymy urządzenie
  15. $pp = New-Object Microsoft.DirectX.Direct3D.PresentParameters
  16. $pp.BackBufferCount = 1
  17. $pp.Windowed = $true
  18. $pp.SwapEffect = [Microsoft.DirectX.Direct3D.SwapEffect]::Discard
  19. $pp.DeviceWindow = $form
  20. $pp.PresentationInterval = [Microsoft.DirectX.Direct3D.PresentInterval]::Immediate
  21. $dev = New-Object Microsoft.DirectX.Direct3D.Device @(0,
  22.     [Microsoft.DirectX.Direct3D.DeviceType]::Hardware, $form,
  23.     [Microsoft.DirectX.Direct3D.CreateFlags]::HardwareVertexProcessing, $pp)
  24.    
  25. # Przygotowujemy się do rysowania
  26. $dev.RenderState.Lighting = $false  # Wyłączamy oświetlenie
  27. $tri = New-Object Microsoft.DirectX.Direct3D.CustomVertex+PositionColored[] @(3)
  28. $tri[0] = New-Object Microsoft.DirectX.Direct3D.CustomVertex+PositionColored @(
  29.     0.0, 0.0, 0.5, [Drawing.Color]::Blue.ToArgb())
  30. $tri[1] = New-Object Microsoft.DirectX.Direct3D.CustomVertex+PositionColored @(
  31.     0.5, -0.5, 0.5, [Drawing.Color]::Red.ToArgb())
  32. $tri[2] = New-Object Microsoft.DirectX.Direct3D.CustomVertex+PositionColored @(
  33.     -0.5, -0.5, 0.5, [Drawing.Color]::Green.ToArgb())
  34.  
  35. # Wyświetlamy
  36. [Windows.Forms.Application]::EnableVisualStyles()
  37. $form.Show()
  38. $time = 0
  39. $lastTickCount = [Environment]::TickCount
  40.  
  41. # Pętlimy się
  42. while ($time -lt 5000) {
  43.     # Przetwarzanie komunikatów
  44.     [Windows.Forms.Application]::DoEvents()
  45.     $time += [Environment]::TickCount - $lastTickCount
  46.     $lastTickCount = [Environment]::TickCount
  47.    
  48.     # Rysujemy
  49.     $dev.Clear([Microsoft.DirectX.Direct3D.ClearFlags]::Target,
  50.         [Drawing.Color]::Lime, [float]1.0, 0)
  51.     $dev.BeginScene()
  52.         # Ustawiamy macierz obrotu
  53.         $angle = (10 * $time / 1000.0) / (2 * [Math]::PI)
  54.         $dev.Transform.World = [Microsoft.DirectX.Matrix]::RotationZ($angle)
  55.        
  56.  
  57.         # Rysujemy trójkąt
  58.         $dev.VertexFormat = [Microsoft.DirectX.Direct3D.CustomVertex+PositionColored]::Format
  59.         $dev.DrawUserPrimitives([Microsoft.DirectX.Direct3D.PrimitiveType]::TriangleList,
  60.             1, $tri)
  61.     $dev.EndScene()
  62.     $dev.Present()
  63. }

Przyznam, że byłem mocno zaskoczony, iż taki trik jest w ogóle możliwy przy pomocy czegoś, co w założeniu jest tylko powłoką tekstową dla poleceń administracyjnych. A tu proszę: DirectX w całej (aczkolwiek zarządzanej) okazałości!
Nietrudno rzecz jasna zauważyć, że powyższy skrypt jest w dużym stopniu tłumaczeniem na język PowerShella odpowiedniego kodu, który mógłby zostać napisany w dowolnym języku programowania z platformy .NET. Trzeba było jedynie poradzić sobie z pewnymi niedogodnościami, jak na przykład koniecznością ręcznego załadowania assemblies czy jakimś obejściem braku sensownej możliwości reakcji na zdarzenia – tutaj “program” po prostu kończy się po 5 sekundach.

Właśnie ta niemożność sprawia, że tandem PowerShell + DirectX zapewne nie ma przed sobą świetlanej przyszłości w grach :) Przez chwilę zastanawiałem się, czy wobec tego nie da się go użyć do tworzenia dem… Niestety, już powyższy skrypt zajmuje ponad 2 kilobajty, nie potrafiąc przy tym zbyt wiele, więc ta możliwość też prawdopodobnie odpada.
Pozostaje zatem pokazywanie podobnych trików linuksowcom i wytykanie im, że ich bash czegoś takiego nie potrafi ;D

Tags: , ,
Author: Xion, posted under Applications » 13 comments

Nadmuchiwanie obiektów

2008-06-08 15:24

Od kilku dni nadspodziewanie popularnym sportem jest piłka nożna, co zapewne nie jest przypadkowe ;-) A jeśli już chodzi o piłkę, to musi być ona odpowiedniej jakości. I mówię tu o tym niewielkim, prawie okrągłym obiekcie: aby był przydatny, musi być… nadmuchany :) I właśnie o ‘nadmuchiwaniu’ powiem dzisiaj słów kilka.
Chodzi mi oczywiście o graficzny efekt rozszerzania się obiektu 3D, wyglądający tak, jakby ktoś w ów obiekt pompował powietrze. Można by pomyśleć, że osiągnięcie go jest niezmiernie trudne, bo przecież wchodząca w grę mechanika płynów (ruch gazu “wypełniającego” obiekt) jest jakąś kosmiczną fizykę. Ale – jak to często bywa – przybliżony a wyglądający niemal równie dobrze rezultat możemy dostać o wiele mniejszym wysiłkiem.

Jak? Sztuczka jest bardzo prosta. Aby nasz mesh zaczął się rozciągać na wszystkie strony, należy po prostu odpowiednio poprzesuwać mu wierzchołki. Wspomniane ‘wszystkie strony’ oznaczają tak naprawdę tyle, że każdy punkt powierzchni obiektu oddala się od niej w kierunku prostopadłym. Kierunek tego ruchu jest wyznaczony po prostu przez normalną.
Efekt jest w istocie trywialny i jego kod w HLSL/Cg może wyglądać na przykład tak:

  1. float fPumpFactor;  // współczynnik nadmuchania obiektu
  2.  
  3. struct VS_INPUT
  4. {
  5.     float3 Position : POSITION;
  6.     float3 Normal : NORMAL;
  7.     // ...
  8. }
  9.  
  10. void vs_main(VS_INPUT In, /* ... */)
  11. {
  12.     // nadmuchujemy
  13.     In.Position += fPumpFactor * normalize(In.Normal);
  14.  
  15.     // (reszta vertex shadera)
  16. }

Wśród zastosowań tego prostego triku można wymienić chociażby wyświetlanie poświaty wokół obiektów. Wystarczy do tego narysować obiekt najpierw w wersji zwykłej, a potem półprzezroczystej i nieco napompowanej.

A tak prezentują się rezultaty, gdy zaczniemy nadmuchiwać poczciwą futbolówkę:

Nadmuchana piłka nożna (PF = -1) Nadmuchana piłka nożna (PF = 2) Nadmuchana piłka nożna (PF = 8)

Na Euro jak znalazł ;]

Tags: ,
Author: Xion, posted under Programming » 5 comments

Skróty i linki NTFS

2008-06-07 15:26

Tworzenie skrótu w Windows VistaSystem Windows od niepamiętnych czasów (a dokładniej od wersji 95) pozwala na tworzenie skrótów (shortcut), czyli plików będących odwołaniami do innych plików lub katalogów. Skróty mają zwykle rozszerzenie .lnk i występują głównie w katalogach tworzących strukturę Menu Start.
Wewnętrznie nie ma w nich nic pomysłowego, gdyż są to zwykłe pliki w formacie na wpółbinarnym, zawierające docelową ścieżkę lub URI (np. adres internetowy). Ich obsługa realizowana jest na poziomie Eksploratora Windows, więc nie są one specjalnie funkcjonalne. Otwarcie pliku skrótu w dowolnym programie nie spowoduje na przykład odczytania zawartości docelowego pliku, lecz samego skrótu (który zwykle ma kilkaset bajtów). Podobnie skrót do katalogu Foo o nazwie Bar.lnk nie spowoduje, że do pliku Foo/Coś.txt odwołamy się poprzez Bar.lnk/Coś.txt.

Ilustracja działania hardlinków
Ilustracja działania linków twardych
(Źródło: Wikipedia)

Taką funkcjonalność zapewniają jednak linki twarde i symboliczne, obecne w nowszym wersjach NTFS. Są one bardzo podobne do swoich odpowiedników w systemach plików ext2 i ext3 (uniksowych). I tak:

  • Link twardy (hardlink) to jakby alternatywna nazwa dla pliku, czyli nowa pozycja systemu plików odwołująca się do tych samych danych. Używając którejkolwiek z nich, można zmienić zawartość pliku i modyfikacje te będące widoczne dla innych, nawet jeśli uzyskają oni dostęp do pliku za pomocą innych jego nazw.
    W Windows 2000 i nowszych linki twarde można tworzyć poleceniem fsutil hardlink create link cel, a w Windows Vista dodatkowo mklink /H link cel. Programowo robi się funkcją WinAPI o nazwie CreateHardLink.
  • Link symboliczny (symlink) jest z kolei łączem do istniejącej nazwy pliku lub katalogu; zamiast do faktycznych danych na dysku odwołuje się więc do innego elementu systemu plików. To właściwie taki skrót pozbawiony ograniczeń, o których wspominałem na początku. Możliwe jest jednak, aby programy operowały bezpośrednio na linkach symbolicznych, o ile odpowiednio ładnie o to poproszą :)
    W miarę porządna implementacja obsługi symlinków jest niestety zawarta dopiero w Windows Vista; można je tworzyć programem mklink (trzeba jednak zaznaczać jawnie, czy robimy link do pliku czy do katalogu). We wcześniejszych wersjach możliwe jest jedynie tworzenie NTFS junctions, będących “linkami” tylko do katalogów oraz obarczonych innymi ograniczeniami (na przykład Eksplorator w Windows XP dość słabo sobie z nimi radzi).

Jak nietrudno zauważyć, podstawową zaletą linków nad zwykłymi skrótami jest to, że te pierwsze są obsługiwane na poziomie systemu plików. Wobec tego działają one w dowolnym programie i zupełnie przezroczyście dla aplikacji. Trochę szkoda, że ten przydatny drobiazg pochodzący z systemów uniksowych dopiero teraz pojawia się w Windows… ale przecież lepiej późno niż wcale ;]

Tags: ,
Author: Xion, posted under Programming » 3 comments

O (nie)zawodności TCP

2008-06-06 20:43

Dowiadując się, czym jest protokół TCP, można przy okazji usłyszeć lub przeczytać, że jest on niezawodny (reliable). Można wtedy pomyśleć, że to jakiś rodzaj białej magii – zwłaszcza, gdy pomyślimy sobie, jakie przeszkody mogą spotkać przesyłany kawałek danych podczas podróży tysiącami kilometrów kabli (a ostatnio i bez nich). Zatory w transmisji, źle skonfigurowane routery, nagła zmiana topologii sieci, i tak dalej… Mimo to niektóre programistyczne interfejsy próbują nam wmówić, że odczyt i zapis danych “w sieci” jest w gruncie rzeczy niemal identyczny np. z dostępem do dysku. To pewnie też skutek “myślenia magicznego” na temat pojęcia niezawodności w kontekście TCP.

A w praktyce nie kryje się za nim żadna magia. Niezawodność TCP ma swoje granice i obsługuje dokładnie tyle możliwych sytuacji i zdarzeń losowych, ile zostało przewidzianych – jawnie lub nie – w specyfikacji tego protokołu. (Zawartej w RFC 793, jeśli kogokolwiek ona interesuje ;]). Analogicznie jest na przykład z dostępem do dysków wymiennych: stare wersje Windows potrafiły radośnie krzyknąć sławetnym bluescreenem, gdy użytkownik ośmielił się wyciągnąć dysk z napędu w trakcie pracy aplikacji, która z niego korzystała. Była to bowiem sytuacja nieprzewidziana na odpowiednio wysokiej warstwie systemu.
Jakie więc niespodziewane sytuacje i problemy dotyczące TCP należy przewidywać, jeśli piszemy programy sieciowe? Jest ich przynajmniej kilka:

  • Pakiety TCP po drodze od nadawcy i odbiorcy mogą ulegać podzieleniu (fragmentacji) w celu przepchnięcia ich przez podsieci o różnych możliwościach przesyłu. Wszystkie kawałki są oczywiście składane przez odbiorcę w miarę ich napływania wraz z dodatkowymi informacjami, pozwalającymi na odtworzenie kolejności bajtów. Jednak fragmentacja sprawia, że nie musimy odebrać danych w porcjach tej samej długości, w jakiej były wysyłane. Dowolna ilość wywołań funkcji typu Send u nadawcy może przekładać się na równie dowolną liczbę wywołań Receive w celu odebrania wysłanych informacji. Stąd wynika konieczność rozróżniania porcji danych we własnym zakresie, o czym pisałem jakiś czas temu.
  • Połączenie TCP może się zakończyć się nieoczekiwanie, jak choćby poprzez nagłe zakończenie wykorzystującego je procesu u jednej ze stron komunikacji. Wykrycie takiej sytuacji polega niestety wyłącznie na opóźnieniach (timeout) w otrzymywaniu pakietów potwierdzających (ACK) dostarczanie danych. To sprawia, że nie można odróżnić zerwania połączenia od zatorów w transmisji na poziomie samego protokołu TCP.
    Dlatego też trzeba sobie z tym radzić na wyższym poziomie, implementując w protokołach aplikacyjnych mechanizmy typu ping-pong do okresowego sprawdzania, czy połączenie “żyje”. Należy przy tym sprawdzać czas odpowiedzi nie względem jakichś twardych limitów, tylko poprzednio rejestrowanych interwałów.
  • Diagram stanów połączenia TCP
    Diagram stanów
    połączenia TCP

    Wreszcie, połączenie TCP można też zakończyć grzecznie (wymianą pakietów z flagami: FIN, FIN/ACK i ACK), co powinno dać się wykryć przez sieciowy interfejs programistyczny. W praktyce bywają z tym problemy, a jako takie powiadamianie o rozłączeniu działa tym lepiej, im niższy poziom API jest używany. W miarę pewnie wygląda to na warstwie POSIX-owych gniazdek (w Windows zaimplementowanych jako biblioteka WinSock) oraz w ich bezpośrednim opakowaniu na platformie .NET (System.Net.Sockets.Socket) lub w Javie (java.net.Socket). Wraz ze wzrostem poziomu abstrakcji (jak chociażby w specjalizacjach “sieciowych” strumieni I/O) sprawa wygląda już nieco gorzej…

Z niezawodnością TCP nie ma co więc przesadzać. W szczególności nie powinniśmy oczekiwać, że zapewni nam ona ochronę przed wszystkimi wyjątkowymi sytuacjami, jakie mogą wydarzyć się podczas komunikacji sieciowej. O przynajmniej kilku musimy pomyśleć samodzielnie.

Tags: , ,
Author: Xion, posted under Internet, Programming » Comments Off on O (nie)zawodności TCP

Statyczne składowe i takież konstruktory

2008-06-04 23:30

Wiadomo, że konstruktor to specjalna metoda, która jest wywoływana przy tworzeniu nowego obiektu i ma za zadanie go zainicjalizować. Okazuje się, że w innej wersji “konstruktor” (albo coś, co go przypomina) może służyć do inicjalizacji nie obiektu, lecz samej klasy. A co takiego ma klasa, że należy czasem zadbać o jej prawidłową inicjalizację? Ano chociażby składowe statyczne – wspólne dla wszystkich obiektów.
W C# możemy sobie zdefiniować statyczny konstruktor, który może się tym zająć – jak również (niemal) czymkolwiek innym. Taki konstruktor, podobnie jak zwykły ma postać metody o tej samej co klasa nazwie, lecz jest opatrzony modyfikatorem static. Zostaje on wywołany przed stworzeniem pierwszego obiektu klasy lub próbą dostępu do jakiejkolwiek składowej statycznej. Całkiem praktyczne, prawda?
Coś podobnego ma również Java, a zwie się to oryginalnie ‘statycznym inicjalizatorem’. W odróżnieniu od wariantu z C#, inicjalizator ten jest wywoływany wcześniej – już w momencie załadowania klasy przez maszynę wirtualną. Właściwie jednak nie ma to wielkiego znaczenia, bo efekt jest analogiczny: jeśli ów inicjalizator ma zrobić coś przed pierwszym użyciem klasy, na pewno zostanie to zrobione. Jego kod pisze się w definicji klasy, w bloku otoczonym nawiasami klamrowymi i opatrzonym – a jakże – słówkiem static.

A jak pod tym względem wypada C++? No cóż, jak zwykle blado :) Kruczkiem standardu jest fakt, że wszelkie składowe statyczne klas mają niezdefiniowaną kolejność inicjalizacji, jeśli są przypisane do odrębnych modułów (plików .cpp). Jeśli więc takie składowe zależą od siebie, to wynikiem mogą być tylko kłopoty.
Poradzić na to można dwojako – zależnie od tego, którą zaletę statycznych konstruktorów chcemy wykorzystać. Jeżeli na przykład chcemy, aby jakaś zmienna statyczna lub globalna była zainicjowana niezależnie od tego, gdzie i kiedy chcemy ją użyć, najlepiej uczynić ją lokalną statyczną zmienną w funkcji:

  1. Foo& GetFoo() { static Foo foo; return foo; }

Jeśli z kolei musimy mieć pewność, że przed stworzeniem obiektu naszej klasy zostaną wykonane jakieś dodatkowe czynności, to możemy to częściowo osiągnąć za pomocą statycznej flagi:

  1. class Foo
  2. {
  3.     public:
  4.         Foo()
  5.         {
  6.             if (!ms_bInitialized)
  7.             {
  8.                   // (czynności konieczne przed użyciem klasy)
  9.                   ms_bInitialized = true;
  10.             }
  11.         }
  12. };
  13. Foo::ms_bInitialized = false;

Niezależnie jednak od tego, co jest nam akurat potrzebne, nie powinniśmy nigdy zapominać o rozważeniu zależności między składowymi statycznymi klas i/lub zmiennymi globalnymi w naszym kodzie, jeśli chcemy uniknąć niezdefiniowanego zachowania. Bo wtedy po prostu wszystko się zdarzyć może :]

Tags: , , , ,
Author: Xion, posted under Programming » 3 comments

Triki z PowerShellem #3 – PowerGUI

2008-06-03 20:29

Logo PowerGUIW Windows większość czynności administracyjnych można wykonać przy pomocy interfejsu graficznego. Wraz z wprowadzeniem PowerShella częściowo się to zmieniło, bo – jak to już kilka razy pokazywałem – stanowi on bardzo ciekawą tekstową alternatywę. Istnieje jednak narzędzie, które zamyka to kółeczko i powraca do interfejsu graficznego – to PowerGUI.
Screen z PowerGUIPomysł wydawać się może dziwny, bo przecież GUI nigdy nie osiągnie tego, co jest największą zaletą dobrej konsolki i powłoki tekstowej – ogromnej elastyczności. PowerGUI radzi sobie jednak całkiem nieźle, oferując spore możliwości dostosowywania tego, jakie informacje chcemy przeglądać i jakie dodatkowe akcje możemy na nich wykonać. Obie te rzeczy koduje się po prostu za pomocą poleceń PowerShella; mamy tu elementy zwane script nodes, które wyświetlane są w formie drzewka i po wybraniu prezentują rezultaty jakiejś komendy, np. listę wszystkich uruchomionych procesów (Get-Process). Dodatkowo możemy przypisać im też akcje wykonywane na zwróconych elementach lub odwołania do innych kolekcji obiektów (np. usług zależnych od danej).
Ogólnie pomysł wydaje się całkiem zgrabny i ma potencjał oszczędzania czasu – zwłaszcza że klepanie dość rozwlekłych komend PowerShella może być raczej męczące.

Screen z PowerGUi Script EditorWedług mnie znacznie przydatniejszą częścią PowerGUI jest dołączony edytor skryptów. To nic innego, jak (niemal) pełnowartościowe IDE do skryptów .ps1. Oprócz kolorowania składni oferuje ono debugowanie przy pomocy pracy krokowej i breakpointów oraz podglądanie wartości zmiennych – czyli prawie wszystko, co programiście do szczęścia potrzebne :)
I właśnie ten edytor jest, jak sądzę, najważniejszych powodem, dla którego powinniśmy rzucić okiem na PowerGUI, jeśli przynajmniej od czasu do czasu używamy PowerShella. Nie od rzeczy jest też argument, że cały ten pakiet licencjonowany jest jako freeware, więc możemy go używać bez ograniczeń do dowolnych celów. Zanim więc druga wersja PowerShella (która ma oferować między innymi środowisko graficzne) wyjdzie w świat, jest to całkiem rozsądna propozycja.

Tags: ,
Author: Xion, posted under Applications » 2 comments
 


© 2017 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.