niedziela, 31 marca 2013

Get-Date w PowerShell

Get-Date jest poleceniem wyświetlającym aktualną date i godzinę. Zamiast Get-Date możesz użyć [DateTime]::Now. Przy okazji muszę się przyznać, że zawsze mam problemy z formatem datetime dla Get-Date.

Co ciekawego można zrobić z Get-Date. Na przykład możesz sprawdzić jakie procesy działają dłużej niż dany okres czasu. Stwórzmy zmienną $1HourFromNow, która będzie trzymała date przed 1 godziną i wybierzmy wszystkie procesy, które jeszcze działają.
PS>$1HourFromNow = (get-date).AddHours(-1)
PS>Get-Process |where {$_.StartTime -ge $1HourFromNow }

Innym ciekawym skryptem jest wybranie wszystkich plików z danego katalogu, które w przeciągu ostatniego dnia był modyfikowane.
PS> $1DayFromNow = [DateTime]::Now.AddDays(-1)
PS>gci -recurse | where {$1DayFromNow -le $_.LastWriteTime }

Power Collections

Power Collectons jest biblioteką powstałą w 2005 roku na platformie .NET Framework 2.0 napisanej przez firmę Wintellect. Jest to zapomniana biblioteka. Była napisana, kiedy jeszcze nie było LINQa.
Za pomocą tej biblioteki możesz wykonać iloczyn kartezjański dla kart:
var kolory = new List<string> {"Trefl", "Karo", "Kier", "Pik"};
var figury = new List<string> {"As", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Walet", "Dama", "Król"};

var karty = Algorithms.CartesianProduct(figury,kolory)
    .Select(x=>x.First + " " + x.Second)
    .ToList();

foreach (var karta in karty)
{
    Console.WriteLine(karta);
}
I jeszcze potasować te karty i zagrać w pokera :)
var kartyNaFlopie = Algorithms.RandomSubset(potasowaneKarty, 3);
foreach (  var karta in kartyNaFlopie)
{
    Console.WriteLine(karta);
}
Oprócz tego za pomoca Power Collections możesz dokonać rotacji listy.
string word = "Arkadiusz Beer ";         
for (int i = 0; i < word.Length; i++)
{
    var builder = new StringBuilder();
    Algorithms.Rotate(word.ToList(), i)
        .ToList()
        .ForEach(c=> builder.Append(c));
    Console.WriteLine(builder);
}

Power Collections posiada typy, jakich może ci brakować w BCL (m.in. MultiDictionary<TKey, TValue> czy OrderedBag<T>). Zachęcam za do sprawdzenia tej biblioteki.

czwartek, 28 marca 2013

Czytelność regex

Mam pomysł na polepszenie czytelności regexów.
Dajmy na to, że ktoś stworzył walidację dla maila. Zapisał wzorzec w takiej postaci:
    const string regexPattern = 
@"\b(?<name>[A-Za-z0-9._%+-]+)@(?<domain>([A-Za-z0-9-]+\.)+[A-Za-z]{2,4})\b";
W takiej postaci ciężko jest (przynajmniej dla mnie) ciężko wywnioskować co może przedstawiać dany wzorzec. Proponuje inną postać zapisu takiego stringa:
#region RegExs
    const string regexPattern = @"
\b                  #znak początku wyrazu
(?<name>            #początek grupy [name]
[A-Za-z0-9._%+-]        #dozwolone znaki w nazwie loginu 
+                       #  1..* wcześniejszych znaków
)                   #zakończenie grupy name 
@                   #małpa
(?<domain>          #początek grupy [domain]
(                       #początek sub-domeny
[A-Za-z0-9-]+              #nazwa członu sub-domeny
\.                         #kropka między członami sub-domen
)                       #koniec sub-domeny
+                       # 1..* członów sub-domen
[A-Za-z]                #dozwolone nazwy w top-level-domain
{2,4}                   # 2..4 wcześniejszych znaków  
)                   #zakończenie grupy doamin
\b                  #znak końca wyrazu
";
#endregion
Tak zapisany regex jest lepiej opisany.
  • Wiemy w jakim przedziale przedstawia się dana grupa
  • Szybko zauważamy nazwy grup
  • Mamy opisane wszystkie symbole
  • Znamy dozwolone znaki
  • Obszar wzorców jest zapisany w regionie, więc możemy go ukryć
Mam nadzieję, że pomysł ci się podoba.



sobota, 23 marca 2013

Astronauci Architektury

Każda osoba pracowała albo słyszała o architekcie, który stracił kontakt z ziemią.
Taki architekt jest nazywany "astronautem".


Jest im bardzo ciężko zacząć pisać produktywny kod, ponieważ nie mogą przestać rozmyślać o architekturze. Są jak astronauci w przestrzeni kosmicznej. Wcześniej bujali w obłokach, ale teraz to są na takiej wysokości, że nie ma tlenu i "ważne" sprawy są oddalone od nich o setki kilometrów. Muszą założyć kask. Nie widzą już szczegółów znajdujących się na ziemi. Jeżeli zdjęli by kask to prawdopodobnie mogli by się udusić. Na ogół pracują dla wielkich korporacji, które mogą sobie pozwolić na nieproduktywne rozmyślanie nad architekturą.


Joel Spolski już wcześniej pisał o takich architektach. Omówił ten problem na przykładzie mody na architekturę "Peer-to-Peer". Ludzie byli zafascynowani Napsterem, torrentami i eMule. Wszystko te projekty działają na p2p. Architekci zaczęli rozmyślać jak wbudować p2p w swoich projektach. Były tworzone konferencje o p2p. I nagle ... p2p umarło.


Astronauta Architektury powie ci: "czy możesz sobie wyobrazić aplikację, która tak samo jak torrenty będzie przesyłała ważne dane". Potem powie coś takiego jak: "wyobraź to sobie, już nigdy nie będziesz musiał pisać połączenia klient-server" Ten przykład nie jest tylko dla p2p. Równie dobrze może odnosić się do XMLa, PL/SQL'a, NoSQL czy do innego dowolnego frameworka lub technologię, na którą jest teraz moda.

wtorek, 19 marca 2013

Z Func do IEqualityComparer

Brakuje mi jednej klasy w BCL, która mogła by stworzyć obiekt implementujący IEqualityComparer z wyrażenia lambda . Ten temat był już wałkowany, ale pomimo tego napiszę czego mi brakuje i jakie jest zastosowanie.

Mamy klasę:
public class Value
{
    public int IntValue { get; set; }
    public string StringValue { get; set; }
    public override string ToString()
    {
        return IntValue + "_" + StringValue;
    }
}

Tworzymy comperer (klasa porównująca dwa obiekty), w którym podajemy funkcję zwracającą informację po jakim będziemy porównywać obiekty. Ta funkcja będzie nam potrzebne do tworzenia hash kodu.
public class KeyEqualityComparer<T> : IEqualityComparer<T>
{
    public Func<T, object> _keyToCompar { get; private set; }

    public KeyEqualityComparer(Func<T, object> keyToCompar)
    {
        _keyToCompar = keyToCompar;
    }

    public bool Equals(T x, T y)
    {
        return _keyToCompar(x).Equals(_keyToCompar(y));
    }

    public int GetHashCode(T obj)
    {
        return _keyToCompar(obj).GetHashCode();
    }
}

Aby przedstawić KeyEqualityComparer wystarczy wywołać następujący kod:
var list = new List<Value>
{
    new Value {IntValue = 1, StringValue = "One "},
    new Value {IntValue = 1, StringValue = "Two"}
};

var distinctList1 = list.Distinct(new KeyEqualityComparer<Value>(x =>x.IntValue));

Dodatkowo możemy stworzyć extension method:
public static IEqualityComparer<T> ToEqualityComparer<T>(this  Func<T, object> func)
{
    KeyEqualityComparer<T> equalityComparer = new KeyEqualityComparer<T>(func);
    return equalityComparer;
}

I wtedy możemy operować za pomocą wyrażeniu lambda:
Func<Value, object> keyToCompare = x => x.IntValue;
var distinctList = list.Distinct(keyToCompare.ToEqualityComparer());


piątek, 15 marca 2013

PowerShell w matematyce

PowerShell jest fantastycznym narzędziem do poprawienia swojej produktywności. Może przydać się w prostych zadaniach matematycznych.


Między innymi możesz w szybki sposób sprawdzić co zwraca dane wyrażenie matematyczne:
PS>19 * 17 / 13 + 11 - 7
28.8461538461538
Ale należy uważać, gdyż PS nie kieruje się matematyczną kolejnością wykonywana działań, dlatego poniżysz wynik jest inny niż spodziewany:
PS>2 + 2 * 2
6
PowerShell sprawdza jaka operacja jest na pierwszym miejscu oraz jaki jest typ pierwszej zmiennej. Wywołując wyrażenie 1+"2" mamy inny wynik niż wywołując "1"+2.
PS>1+ "2"
3

PS>"1" + 2 
"12"
Śmieszną możliwością PS jest sposób mnożenia stringa:)
PS>"z" * 5 + "...."
zzzzz....
Jak będziesz potrzebował przeliterować od 1 do 10 to wystarczy zapisać 1..10 (poniżej przykład)
PS>write-host (1..10) -NoNewLine -separator " _ "
1 _ 2 _ 3 _ 4 _ 5 _ 6 _ 7 _ 8 _ 9 _ 10
Taki zapis jest znany z innych języków. Pierwszy raz zobaczyłem taki sposób inicjalizacji w Matlabie. Dodawanie zakresów jest też bardzo intuicyjne. Aby przeiterować od -5 do 5 bez zera to wystarczy zapisać:
PS>write-host ( -5..-1 + 1..5 ) -NoNewLine -separator " _ "
-5 _ -4 _ -3 _ -2 _ -1 _ 1 _ 2 _ 3 _ 4 _ 5
Do tego masz możliwości użycia klasy [math], która posiada najważniejsze funkcje matematyczne:
PS> [math] | Get-Member -Static 
I tak możemy w szybki sposób obliczyć procent składany
PS> $initialInvestment * [math]::pow(1+$interestRate, $times) 
PS> 1000 * [math]::pow(1+0.05, 2)
1102,5
Natomiast, aby obliczyć na jaki procent w skali roku zwróciła się inwestycja wystarczy napisać:
PS>[math]::pow($value/$initialInvestment,1/$times) - 1
PS>[math]::pow(1102/1000,1/2) - 1
0,0497618777608568
Co jest bardzo ciekawe w PS to możliwość operacji na jednostkach pamięci.
PS> 1MB
1048576

PS> 9MB
9437184

PS> 1TB
1099511627776
Możesz przedstawić wielkość jednostki pamięci w innej jednostce, na przykład w postaci megabajtów:
PS>1TB / 1MB
1048576
Czasami taki zapis pomaga przy obliczaniu zajmowanej przestrzeni na dysku.
PS>"{0:n3}"-f ((gwmi win32_logicaldisk -Filter "DeviceID='C:'").freespace/1GB)
Uważam, że PowerShell jest narzędziem matematycznym do bardzo prostych zadań. PS nigdy nie będzie (nigdy nie mów NIGDY) narzędziem dla matematyków, ale w pracy administratora fantastycznie się sprawdza jako proste narzędzie matematyczne.

środa, 13 marca 2013

Wizualizacja społeczeństwa na świecie

Miałem przyjemność zapoznania się z narzędziem, które wizualizuje dane statystyczne. To narzędzie nazywa się GapMinder. Za pomocą tego narzędzia można ciekawe rzeczy wywnioskować np. ilość urodzonych dzieci na jedną matkę jest odwrotnie proporcjonalne do PKB, albo wraz ze wzrostem długości życia wzrasta PKB. Za pomocą tego narzędziu można znaleźć pewną korelację rządzącą światem np. PBK i przeżywalność urodzonych dzieci.



Bardzo zachęcam do pobawienia się narzędziem. Poniżej zamieszczam filmiki pokazujące co można z GapMinderem zrobić.












Zastanawiam się czy można zastosować ten tool w nauczaniu dzieci w polskich szkołach. Jak ja chodziłem do szkoły to nie miałem takich możliwości wizualizacji danych. Gdybym jednak miał taką możliwość, to do tej pory bym został statystykoholikiem :)





Możesz pobrac wersje desktopową GapMindera pod tym adresem


wtorek, 12 marca 2013

Generowanie hasła w PowerShell

Wydaje mi się, że jedno z najczęściej wykonywanych zadań administratorów to jest generowanie nowego hasła dla użytkownika :) Ten post przedstawi Ci w jakie sposoby będziesz mógł wygenerować hasło.

Możesz skorzystać z funkcji Get-Random. Ta funkcja będzie losowała znaki ASCII. Poniżej jest kod:
$length = 8 #długość znaków hasła
$arr = 
33..33 + # znak: !
35..46 + # znaki: #$%&'()*+,-. 
48..57 + # znaki: 0123456789
64..90 + # znaki: @A-Z
97..122  # znaki: a-z 

$result= Get-Random  -count $length -input $arr | %{ [char]$_} 
[string] -join  $result  

Innym sposobem na wygenerowanie hasła jest użycie genreator GUID. Masz ograniczenie do 32 znaków, ale wydaje mi się że nie ma takiego szaleńca, który by wygenerował hasło dla użytkownika składające się z ponad 32 znaków :)
$length = 8
$guid = [Guid]::NewGuid().ToString() -replace "-", "" 
$guid.Substring(0,$length)

Jeżeli chciałbyś skorzystać z dedykowanej klasy do generowania hasła z .NET to możesz użyć Membership.GeneratePassword.
$length = 8
[Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null
[System.Web.Security.Membership]::GeneratePassword($length,0)

Ale pomimo tych wszystkich udogodnień i tak chciałem stworzyć swoją własną funkcję do generowania hasła. Poniżej jest skrypt:
function Generate-Password 
{
  Param(
     [int] $length=8,
     [int] $numberOfNonAlphanumericCharacters=0
)

$allowedChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
if ($numberOfNonAlphanumericCharacters -gt 0)
{
     $allowedChars += "-&@#%!*$?_";
}
$rnd = new-object System.Random    
$passwordChars = @()
for ($i = 0; $i -lt $length; $i++) 
{ 
  $rndIndex = $rnd.Next(0, $allowedChars.Length)
  $passwordChars += @( $allowedChars[$rndIndex] ) 
}
return [string] -join $passwordChars
}

niedziela, 10 marca 2013

Dynamic pipeline

Wcześniej pisałem o moim wzorcu pipeline. Wzorzec ten ma jeden duży minus. Może być zastosowany dla jednego typu obiektu. Jeżeli obiekt typu T jest daną wejściową to daną wyjściową też musi być typu T. Jeden duży pipeline może składać się z kilku pipeline-ów, w których ta zasada musi być spełniona.




A co jeżeli chcielibyśmy stworzyć pipeline z innym typem wejścia i wyjścia? Wtedy będziesz musiał zastosować type dynamic. Spójrz na klasę podstawową reprezentującą dany krok, która została przedstawiona w poprzednim rozwiązaniu:
public abstract class BaseStep<T>
    {
        protected BaseStep<T> _nextStep;
        public void SetNextStep(BaseStep<T> nextStep)
        {
            _nextStep = nextStep;
        }
        public T Process(T input)
        {
            var items = Handle(input);
            return _nextStep != null ? _nextStep.Process(items) : items;
        }
 
        protected  abstract T Handle(T input);
    }

Zmieńmy w tej klasie type dla następnego kroku, wprowadźmy dodatkowy parametr generyczny, aby odróżnić typ wejściowy od wyjściowego.
Cała klasa bazowa musi dziedziczyć po DynamicObject.
public abstract class ProceseBase<T, TReturn> : DynamicObject
    {
        protected dynamic _nextStep;
        public void SetNextStep(dynamic nextStep)
        {
            _nextStep = nextStep;
        }
        public dynamic Process(T input)
        {
            var items = Handle(input);
            return _nextStep != null ? _nextStep.Process(items) : items;
        }

        protected abstract TReturn Handle(T input);
    }

Taka zmiana pozwoli nam na dowolną modyfikację zwracanych typów obiektu z pipeline.



Przykład użycia wygląda następująco. Dajmy na to, że z wygenerowanych licz, chcemy sprawdzić ile jest licz dla danej pierwszej cyfrą. Dla liczb { 1,11,13,29,32,300 } mamy dla cyfry 1 - 3 liczby, dla 2 - 1 liczba, dla 3 - 2 liczby.
Na samym początku stwórzmy klasę, która będzie reprezentowała pierwszy krok - konwersja na string.
 public class ConvertToStringProcess<T> 
 : ProceseBase<IEnumerable<T>, IEnumerable<string>>
    {
        protected override IEnumerable<string> Handle(IEnumerable<T> input)
        {
            return input.Select(x => x.ToString());
        }
    }  

Następnie krok grupujący oraz krok zliczający liczbę elementów. Każdy z tych kroków ma inny typ wejściowy i wyjściowy.
 public class GroupByFirstCharProcess 
: ProceseBase<IEnumerable<string>, IEnumerable<IGrouping<char,string>>>
    {
        protected override IEnumerable<IGrouping<char, string>> 
Handle(IEnumerable<string> input)
        {
            return input.GroupBy(x => x.First());
        }
    } 

 public class CountItemsDictionary 
: ProceseBase<IEnumerable<IGrouping<char, string>>, Dictionary<char, int>>
    {
        protected override Dictionary<char, int> 
Handle(IEnumerable<IGrouping<char, string>> input)
        {
            return input.ToDictionary(x => x.Key, x => x.Count());
        }
    } 

A na końcu wywołanie dynamic pipelinu. Każde rozwiązanie ma jakieś plusy i minusy. W tym rozwiązaniu minusem jest używanie dynamikc :)
(tutaj, tutaj i tutaj)
 var numbers= HelpClass.GenerateData<int>(x => x * x).Take(300);

 dynamic itemsStrings= new ConvertToStringProcess<int>();
 GroupByFirstCharProcess groupedByFirstChar = new GroupByFirstCharProcess();
 CountItemsDictionary countedItems = new CountItemsDictionary();

 itemsStrings.SetNextStep(groupedByFirstChar);
 groupedByFirstChar.SetNextStep(countedItems);

 var countedNumbers= itemsStrings.Process(numbers);



Problem z lazy w liscie

Jak pisałem wcześniej, klasa Lazy<T> nie zawsze zachowuje się tak jak byś myślał. Poniższy przykład przedstawia mylne działanie listy z 'późnymi' elementami.

Na początku stwórzmy klasę, która będzie zawierała pewną wartość.
      public class Item
        {
            private readonly int _i;
            public Item(int i)
            {
                _i = i;
            }
            public override string ToString()
            {
                return "I: "+_i;
            }
        }

A teraz stwórzmy listę z lazy elementami i te elementy ponumerujemy.
  List<Lazy<Item>> lazyList = new List<Lazy<Item>>();
  for (int i = 0; i < 10; i++)
  {
      lazyList.Add(new Lazy<Item>(() => new Item(i)));
  }
  foreach (var lazyItem in lazyList)
  {
     Console.WriteLine(lazyItem.Value);
  }

Jak uruchomimy aplikację to zamiast ponumerowanych elementów, dostajemy obiekty z tą samą wartością.


sobota, 9 marca 2013

Późne generowanie obiektu

Ostatnio bawiłem się leniwą (późną) inicjalizacją obiektu przez klasę Lazy. Troszkę zaskoczyła mnie jej działanie. Chciałbym powielić jeden obiekt, który ma losowe wartości.
    public class ElementClient
    {
        public string Name = Path
.GetRandomFileName()
.Replace(".", "");

        public Guid Guid = Guid.NewGuid();
        public override string ToString()
        {
            return string.Format("Guid:{0} Name:{1}", Guid, Name);
        }
    }
Mamy pomocniczą metodę wyświetlająca elementy w liście
      private static void Print<T>(IEnumerable<T> elements)
        {
            foreach (var elementClient in elements)
            {
                Console.WriteLine(elementClient);
            }
        }
Jeżeli powielę jeden obiekt to dostaje takie same wartości.
            int repeatNumber = 5;
            var elements = Enumerable.Repeat(new ElementClient(), repeatNumber);
            Print(elements);
Ale chciałbym stworzyć 5 obiekty, które mają różne wartości. Więc muszę wcześniej stworzyć klasę, która inicjalizuje obiekt wtedy gdy dany obiekt będzie potrzebny.
    public class Invoker<T>
    {
        public T Value
        {
            get { return _func(); }
        }
        private Func<T> _func;
        public Invoker(Func<T> func)
        {
            _func = func;
        }
    }
            var elements2 = Enumerable
                .Repeat(new Invoker(() => 
                                        new ElementClient()), repeatNumber)
                .Select(x => x.Value)
                .ToList();
            Print(elements2);

To samo chcemy zrobić za pomocą klasy Lazy<T>
     var elements3 = Enumerable
                .Repeat(new Lazy<ElementClient>(), repeatNumber)
                .Select(x => x.Value)
                .ToList();
            Print(elements3);
Ale dostałem takie same wartości. Uważaj na klasę Lazy<T> - nie zawsze działa tak jak myślisz.

środa, 6 marca 2013

Zmiana rozmiaru zdjęć za pomocą PowerShell

Czy masz może bardzo dużo zdjęć w jednym katalogu, musisz zmienić rozmiar tych zdjęć i za każdym razem uruchamiasz program graficzny, aby zmienić rozmiar zdjęcia??
Ja akurat tak miałem wiele razy :)
Jeśli coś powtarzasz wielokrotnie to postaraj się zautomatyzować tą czynność. Poniżej jest skrypt, który zmienia rozmiar zdjęcia.
function Resize-Image {
[CmdletBinding()]
Param(
     [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] 
     [System.io.FileInfo] $filepath,
     [int] $width=100,
     [int] $height=100,
     [string]$prefix="rs_"
)

PROCESS{
        $filePathFullName = $filepath.FullName
        if( Test-Path $filePathFullName)
        {
            $destName = $prefix+$filepath.name
            $destPath = Join-Path -path  $filepath.DirectoryName $destName
            
            import-bitmap $filePathFullName | resize-bitmap -Width $width -Height $height | export-bitmap  -Path $destPath 
            Write-Host "Resizing into $destPath"
                   
        }
        else {
            Write-Host "Path not found."
            }
        }
}
Przykład użycia jest przedstawiony poniżej:
gci -filter *.bmp |  Resize-Image 

Ten skrypt może u ciebie nie działać, bo prawdopodobnie nie masz PowerShell Community Extensions. Skrypt korzysta z poleceń import-bitmap,resize-bitmap i export-bitmap, które znajdują się w PSCX. Aby zainstalować PSCX, to wystarczy pobrać paczkę ze strony internetowej. Rozpakować do jednej z lokalizacji zawartej w zmiennej $Env:PSModulePath. A na końcu wywołać poniższy skrypt:
Import-Module Pscx -arg ~\PSCX\Pscx.UserPreferences.ps1
Get-Module

Mam nadzieję, że skrypt się przyda :)

wtorek, 5 marca 2013

Problemy z produktywnością


Znasz może ten żart:

Są rodzaje seksu: więzienny, studencki, przedszkolny i filozoficzny.
Więzienny: Jest gdzie, ale nie ma z kim,
Studencki: Jest z kim, ale nie ma gdzie.
Przedszkolny: Jest gdzie, jest z kim, ale nie ma czym.
Filozoficzny: Jest gdzie, jest z kim, ale czy jest sens...?



Wydaje mi się, że tak sam podział może być z problemami produktywności.

Przedszkolny: nie ma zadań, nie wiadomo jak, nie ma narzędzi.
Studencki: są zadania, nie ma wiedzy(jeszcze nie), są narzędzia.
Więzienny: są zadania, jest wiedza, nie ma narzędzi.
Filozoficzny: są zadania, jest wiedza, są narzędzia, ale jaki to ma sens?



Jeżeli jesteś typem przedszkolaka to nie musisz dbać o produktywność bo nie masz zadań. I z tego też powodu wszyscy ci zazdroszczą.

Jeżeli jesteś typem studenta to już powinieneś dbać o produktywność bo są zadania. Pomimo tego, że masz dostęp do narzędzi nie wykorzystujesz je. Mi bardzo brakuje dostępu do DreamSparka. Stamtąd można było pobrać bardzo dużą ilość programów za darmo. Doceniłem to dopiero po studiach.

Jeżeli jesteś typem więźnia to masz zadania i wiedzę, które mogą zwiększyć produktywność. Ale nie masz wymaganych narzędzi. Z taką sytuacją może się spotkać, gdy pracujesz w firmie, gdzie nie ma dostępu do potrzebnych narzędzi.

Jeżeli jesteś filozofem. to masz zadania do zrobienia, potrzebną wiedzę, wymagane narzędzia, ale nie obchodzi cię czy jesteś produktywny. Masz swoje przyzwyczajenia, które nie chcesz zmieniać.


niedziela, 3 marca 2013

Mój wzorzec pipeline

Pipeline to łańcuch połączonych kroków,które procesują informację. Każdy krok dostaje obiekt i wykonuje jakąś akcje na tym obiekcie zanim zostanie wysłany do następnego kroku. Pipeline łączy jednostki procesowania, które mogą być klasami, metodami lub komponentami. Object pipeline składa się z 3 grup: klientów, klasy bazowej oraz z klas przedstawiający dany kroku. Klient tworzy obiekt, który ma być procesowany i wie jaki jest pierwszy krok. Klasa bazowa jest abstrakcyjna, posiada metodą, która zarządza wywołaniem. Pobiera obiekt, przetwarza go a następnie przesyła do następnego kroku. Klasa bazowa posiada też obiekt typu klasy bazowej reprezentujący następny kroków, do której tylko klasy dziedziczące mają dostęp. Klasa z krokiem dziedziczy po klasie bazowej. Schemat jest przedstawiony poniżej:



Na samym początku stwórzmy pomocnicze metody:
public class HelpClass
    {
        public static IEnumerable<T> GenerateData<T>(Func<int, T> func)
        {
            for (int i = 0; ; i++)
            {
                yield return func(i);
            }
        }

        public static DescriptionAttribute GetClassDescriptionAttribute(Type type)
        {
            return type
.GetCustomAttributes(typeof(DescriptionAttribute), false)
.FirstOrDefault() as DescriptionAttribute;
        }
    }
Następnie stwórzmy abstrakcyjną klasę bazową, po której klasy z implementacją kroku będą dziedziczyć.Klasa ta będzie miała abstrakcyjną metodę - Handle(T input).
      public abstract class BaseStep<T>
    {
        protected BaseStep<T> _nextStep;
        public void SetNextStep(BaseStep<T> nextStep)
        {
            _nextStep = nextStep;
        }
        public T HandleProcess(T input)
        {
            var desc = HelpClass
.GetClassDescriptionAttribute(this.GetType());

            if(desc != null)
                Console.WriteLine(desc.Description);
 
            var items = Handle(input);
            return _nextStep != null ? _nextStep.HandleProcess(items) : items;
        }
 
        protected  abstract T Handle(T input);
    }
Teraz możemy napisać poszczególne implementacje kroków. Niech pierwszy krok będzie usuwał pierwszy element w liście, a drugi krok będzie usuwał duplikaty. Skorzystamy z atrybutu Description, aby mieć opis w którym kroku jesteśmy.
      [Description("Filters first element")]
    public class FilterFirstStep<T> : BaseStep<IEnumerable<T>>
    {
        protected override IEnumerable<T> Handle(IEnumerable<T> input)
        {
              return input.Skip(1);
        }
    }
 
    [Description("Filters duplicated elements")]
    public class FilterDuplicatedStep<T> : BaseStep<IEnumerable<T>>
    {
        protected override IEnumerable<T> Handle(IEnumerable<T> input)
        {
            return input.Distinct();
        }
    }
Dodatkowo stwórzmy krok, który będzie zawierał informacje jak długo trwało przetwarzanie listy.
    [Description("Measuring step")]
    public class MeasureStep<T> : BaseStep<IEnumerable<T>>
    {
        public long Elapsed { get; private set; }
        protected override IEnumerable<T> Handle(IEnumerable<T> input)
        {
            Stopwatch stopwatch = Stopwatch.StartNew();
            var result = input.ToList();
            Elapsed = stopwatch.ElapsedMilliseconds;
            return result;
        }
    }
Teraz jak mamy wszystkie kroki to możemy zająć się testowaniem pipelineu.
            Random random = new Random();
            var items = HelpClass.GenerateData(i => random.Next(i)).Take(90000);
            MeasureStep<int> measure = new MeasureStep<int>();
            FilterFirstStep<int> filterFirst= new FilterFirstStep<int>();

            measure.SetNextStep(filterFirst);
            filterFirst.SetNextStep(new FilterDuplicatedStep<int>());


            var hanled = measure
                .HandleProcess(items)
                .ToList();

            Console.WriteLine(measure.Elapsed);
I na konsoli mamy:
Wzorzec object pipeline ma jeden duży minus - dane wejściowe musza być tego samego typu co dane wyjściowe.


Dziedziczenie w c#

Co jakiś czas napotykam na problemy związane z Co- i Contra- wariancją, więc postanowiłem troszkę pobawić się z .NETem. Chciałbym przedstawić dlaczego jest z tym taki problem. Niech poniższy wpis będzie wstępem do większego zagadnienia.
Stwórzmy 2 klasy. Jedna (B) będzie dziedziczyła po drugiej (A)
class A
{
}
 
class B : A
{
}

Aby poprawić czytelność stwórzmy extension method, która będzie określała czy jeden typ dziedziczy od drugiego typu:
 public static class TypeExt
{
 public static bool IsFromType<T>(this Type type)
 {
     return typeof(T).IsAssignableFrom(type);
 }
}

Teraz możemy sprawdzić co zwróci nam ta metoda.
     Console.WriteLine(typeof(A).IsFromType<A>()); //true 
     Console.WriteLine(typeof(B).IsFromType<A>()); //true 
     Console.WriteLine(typeof(A).IsFromType<B>()); //false 

Sprawdzamy jak będzie dla typów generycznych.
 Console.WriteLine(typeof(List<B>).IsFromType<List<B>>()); //true
 Console.WriteLine(typeof(List<B>).IsFromType<IEnumerable<B>>()); //true

Typy generyczne są tak samo traktowane jak 'normalne' typy. Ale co będzie, kiedy argumenty w typach generycznych będą różne lub jeden argument będzie dziedziczony po drugim??
    Console.WriteLine(typeof(List<B>).IsFromType<List<A>>()); //false

Nawet jeżeli typ generyczny będzie taki sam, argumenty w typie generycznym będą inne, ale w relacji dziedziczenia to nie ma zależności. Wtedy musimy porównywać argumenty tych typów generycznych.
public static bool IsGenericArgFromType<T>(this Type type)
{
   var args1 = typeof(T).GetGenericArguments();
   var args2 = type.GetGenericArguments();

   return args1.Length == args2.Length &&
      args1.Zip(args2, (arg1, arg2) => new { arg1, arg2 })
      .All(x => x.arg1.IsAssignableFrom(x.arg2));
}

Console.WriteLine(typeof(List<B>).IsGenericArgFromType<List<A>>()); //true
Console.WriteLine(typeof(List<string>).IsGenericArgFromType<List<object>>()); //true
Pomimo tego, że argumenty w typie generycznym są w relacji dziedziczenia (przyporządkowania) to te dwa type nie są przyporządkowane do siebie. Taki sam problem jest, gdy mamy listę stringów i listę obiektów. W naturalny sposób lista stringów powinna być przyporządkowana do listy obiektów, ale tak nie jest.

SMART - nadużywany akronim

Mam wrażenie, że akronim SMART jest nadużywany. Wszyscy chcą teraz być smart - mądrzy, eleganccy, błyskotliwi, zwinni i sprytni. Więc słówko SMART bardzo łatwo staje się popularne, a zasada o tej samej nazwie ma coraz większą rzeszę zwolenników.



Ostatnio zaglądnąłem pod hasło SMART na Wikipedii, aby sprawdzić ile jest słówek rozwijających ten akronimem. Z tych wszystkich kombinacji można rozwinąć akronim na 13 824 sposobów. Jak jeszcze dołożymy literki ER to jest 580 608 sposobów. Przykład można zobaczyć w poniższym pliku. Wydaje mi się, że najważniejsze nie są literki, ale jaki przekaz niesie dana literka.



Już wcześniej pisałem o tym, że metoda SMART nie wystarcza w realizowaniu celów, ale uważam, że jest bardzo dobrą metodą przy wyznaczaniu celów.

sobota, 2 marca 2013

Zamykanie Windows 8

Musze się przyznać, że jak pierwszy raz uruchomiłem Windows 8 to nie wiedziałem, gdzie jest przycisk do zamykania komputera. Po pewnym czasie w końcu znalazłem. Jeżeli jesteś użytkownikiem Windows 8, to miałeś może taki problem jak ja??



W każdym razie nie o problemach szukania przycisku chciałbym napisać, ale o szybkim zamykaniu systemu.
Na samym początku stwórz skrót ma pulpicie.

Jako program wykonywalny wpisz:

shutdown.exe /s /t 00

Inne opcje są podane na tej stronie.

Polecam wybranie sobie ikonki.


Zaznacz sobie prawym przyciskiem myszy i wybierz "Przypnij do ekranu startowego" ("Pin to Start").



W menu Start przenieś przycisk tam gdzie chcesz. Oczywiście możesz dodać inne opcje zamykania (np. restartowanie).


Na końcu możesz jeszcze usunąć te skróty, które stworzyłeś na pulpicie - usunięcie ich nie wpływa na funkcjonalność okna Start.