czwartek, 31 lipca 2014

Pseudorekurencja w Oracle

Spróbowałem moich sił w oracle w wywołaniach rekurencyjnych. Skorzystałem z klauzury WITH. Tak na prawdę nie są to wywołanie rekurencyjne. Poniżej przedstawiam przykład wyświetlania wartości silni:
with 
Factorial (n,fact) as (
select 
0 as n,
1 as fact
from dual

union all

select 
n +1, (n+1)*fact
from Factorial
where n < 20
)
select * from Factorial 
;
A tutaj przykład wyliczenia liczby ruchów z postaci jawnej dla problemu wieży Hanoi:
with 
hanoi  (n,counts) as (
select 
1 as n,
1 as counts
from dual

union all

select 
n +1, POWER(2,n+1) -1
from hanoi 
where n < 20
)
select * from hanoi  
;
Wśród standardowych przykładów rekurencji zawsze musi wystąpić ciąg Fibonacciego. Zapytanie wyświetlające liczbę oraz wartość fibonacciego dla tej liczb, wygląda następująco:
with 
fibonacci (n,fib, fibadd) as (
select 
0 as n,
0 as fib,
1 as fibadd
from dual

union all

select 
n +1, fibadd, (fib + fibadd)
from fibonacci
where n < 100
)

select n,fib from fibonacci 
;

Jak pewnie zauważyłeś, to nie tworzysz modelu rekurencyjnego z warunkami stopu, ale model iteracyjny z warunkami początkowymi.

poniedziałek, 28 lipca 2014

Produktywne makra Visual Studio

Chcę Ci przedstawić 2 makra, które pomagają mi w pisaniu kodu. Pierwsze makro dodaje nawiasy okrągłe do zaznaczonego tekstu w edytorze. Super się sprawdza makro dla kodu w PowerShell czy dla FSharp. Poniższy kod wystarczy zapisać w makrze VS:
Public Module BracketIt
    Public Sub AddBrackets()
        Dim s As Object = DTE.ActiveWindow.Selection()
        If s.Text.StartsWith("(") And s.Text.EndsWith(")") Then
            s.Text = s.Text.Substring(1, s.Text.Length - 2)
        Else
            s.Text = "(" + s.Text + ")"
        End If
    End Sub
End Module
Skrótem klawiszowym do wywołania tego makra mam ustawione na:
Shift+CTRL+A, Shift+CTRL+B,
Równie dobrze można było dodać nawiasy ostrokątne do edycji plików xml.
Drugim makrem jest asercja sprawdzająca czy wartość jest nullem:
Public Module AddAssert
    Public Sub IsNotNull()
        Dim s As Object = DTE.ActiveWindow.Selection()
        Dim assertStr As String = "Assert.IsNotNull"

        If s.Text.Length > 0 Then
            s.Text = assertStr + "(" + s.Text + ")"
        Else
            s.Text = assertStr
        End If
    End Sub
End Module
A skrótem klawiszowym jest:
Shift+CTRL+A, Shift+CTRL+A
Te 2 makra u mnie się sprawdzają. Jeśli masz swój pomysł na makro to podziel się nim.

niedziela, 27 lipca 2014

Count lines of code

CLOC to tool do wyliczenia liczby plików różnych formatów oraz wylicza ile jest tych linijek kodu oraz komentarzy w tych plikach.Jest to tool, bardzo prosty w działaniu. Zacząłem pisać wrapper na PowerShella.
Pierwsza funkcja już jest:
function Get-Loc
{
    param($location="."
)
    $commandLine = "$location --csv"
    $clocResult = & $clocPath $location --csv
    $indexOfLineCsvToParse = [array]::IndexOf($clocResult, "")
    if($indexOfLineCsvToParse -lt 0)
    {
        throw "cant get empty line in cloc result"
    }
    $csvToparse = $clocResult[$indexOfLineCsvToParse..($clocResult.Length)]
    $csvFeed = ConvertFrom-Csv $csvToparse -Delimiter ',' | select  files,language,blank,comment,code  

    return  $csvFeed | %{
        return New-Object PSObject  -prop @{
                                    Files = [int]($_.files);
                                    Language = $_.language;
                                    Blank = [int]($_.blank);
                                    Comment = [int]($_.comment);
                                    Code = [int]($_.code);
                               }
                    } 
}
Aby wyświetlić statystykę projektów to wystarczy wywołać:
 Get-Loc "C:\ProjectDir"
Skrypt jest dostępny w github'a.

sobota, 19 lipca 2014

Reinstalacja pakietów nuget

Pewnie miałeś taką potrzebę reinstalacji pakietu nuget z poziomu Visual Studio. Domyślnie, nuget nie ma możliwości reinstalacji pakietu w jednej komendzie. Poniżej zamieszczam skrypt do wykonania tego zadania:
function Reinstall-Package {
    param(
        [Parameter(Mandatory = $true)]
        [string]
        $Id,

        [Parameter(Mandatory = $true)]
        [string]
        $Version,

        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [string]
        $ProjectName,

        [switch]
        $Force
    )

    if (-not $ProjectName) {
        $ProjectName = (get-project).ProjectName
    }
    Uninstall-Package -ProjectName $ProjectName -Id $Id -Force:$Force
    Install-Package -ProjectName $ProjectName -Id $Id -Version $Version
}

Przykład wywołania dla reinstalacji danego pakietu dla wszystkich projektów w solucji jest poniżej:
Get-Project -All |
     ?{ $_ | Get-Package | ?{ $_.Id -eq 'bla.bla.bla' } } |
         %{ $_ | Reinstall-Package -Id 'bla.bla.bla' -version 1.0.0 -Force }

Nie będziesz mógł załadować modułów, więc będziesz musiał wywołać skrypt Reinstall-Package z nugetowej konsoli lub możesz dodać tą funkcję do pliku z profilem:
notepad $Profile​

poniedziałek, 14 lipca 2014

Problem ucztujących filozofów w PowerShell

Już wcześniej chciałem przedstawić moje rozwiązanie problemu pięciu ucztujących filozofów, ale jak zwykle ciężko znaleźć chwilkę czasu. Tak na prawdę moje rozwiązanie nie jest ostatecznym rozwiązaniem tego problemu, ale implementacją różnych możliwości uruchomienia symulacji ucztujących filozofów. Aby uruchomić symulację wystarczy uruchomić skrypt:
Run-DPP -showAll

Na ekranie uzyskamy liczby:
Status: 0 0 0 1 0
Meals: 5 2 4 3 3

Górny wiersz określa semafory o wolnych widelcach, a dolny wiersz określa ile razy dany filozof jadł. Z górnego wiersza można odczytać, że widelec przedostatni jest wolny.

Zacząłem rozwiązywać ogólny problem ucztujących n-filozofów. Poniżej przykład statusu dla 10 filozofów:


Symulacja działania filozofów jest na podstawie Jobów. Przy każdym wywołaniu skryptu następuję usunięcie job'ów:
    get-job | Stop-Job
    get-job | Remove-Job 


Na potrzeby rozwiązania problemu, użyto dodatkowego joba, który zarządza wszystkimi filozofami - kelner obsługujący filozofów. Implementacja kelnera jest w pliku Run-Waiter.ps1.
for( $i=0; $i -lt $philosopherNumber ; $i++) 
{
        Start-job -FilePath $scriptPath  -ArgumentList  $i,$scriptLocation -Name "Philo_$i"
} 

Każdy filozof prosi kelnera o widelec (request +1).
Kelner sprawdza listę próśb (request >0) i jak widelce są dostępne, podchodzi do filozofa i pozwala na wzięcie widelca (response +1).
Filozof sprawdza odpowiedz (response >0), bierze widelec i dziękuje za obsługę (request -1).
Kelner odchodzi od filozofa (response -1)
W taki sposób, filozof jest odpowiedzialny za zapis requestów, a kelner odpowiedzialnego za zapis responsów.




Dla kelnera wprowadziłem opcje randomizacji wyboru od którego filozofa za zacząć pytać czy czegoś nie potrzebuje. Częściowo rozwiązanie to rozwiązało problem nadawania priorytetu filozofom parzystym przed innymi filozofami, gdy mamy parzystą liczbę wszystkich filozofów.



W pliku DiningPhilosophersProblemHelper.ps1 są wszystkie funkcje współdzielone między kelnerem, a filozofami. PS nie ma pamięci współdzielonej pomiędzy wszystkie job'y czy procesy. Komunikację między job'ami jest zaimplementowana poprzez zmienne środowiskowe, które są dostępne z poziomu użytkownika:
[Environment]::GetEnvironmentVariable($name, [System.EnvironmentVariableTarget]::User)

Tablica określająca wolne zasoby widelców jest zapisana w zmiennej środowiskowej jako string:
function Set-ArrVariable([string]$name, [array]$arr)
{
    Set-ArrVariableStr $name ($arr  -join ';')
}

Zapis danych do zmiennej środowiskowej na poziomie użytkownika jest naszą sekcją krytyczną. Często można było uzyskać wielokrotne zwiększenie lub zmniejszenie wartości w tablicy:


Synchronizacja zapisu zmiennej środowiskowej jest za pomocą globalnych muteksów dostępnych przez wszystkie job'y. Przykład tworzenia globalnego muteksa jest poniżej:
$UsedForksMutex = new-object  System.Threading.Mutex ($false, 'Global\UsedFork')

Wprowadziłem opcje umierania filozofów, gdy za długo czekają na sztućce (lub na obsługę kelnera).
[bool]$mayStarve = $false
Czas potrzebny dla filozofa na myślenie oraz jedzenie jest ustawiony jako zmienna losowa. Domyślnie jest to wartość jednostkowa.

W planach mam jeszcze dodatnie
- ograniczenia do parzystej liczby filozofów, którzy mogą ubiegać się o sztućce
- pozwolenie filozofom wzięcia widelców, tylko jeżeli 2 z nich są dostępne ( jak na razie filozof bierze jeden widelec, a później próbuje wziąć drugi)
- filozofowie z parzystymi numerami najpierw wybierają widelce po prawej stronie, a filozofowie z numerami nieparzystymi wybierają najpierw widelce po lewej stronie
- rozwiązanie probabilistyczne (losowe wybieranie strony pierwszego widelca, a później znów losowanie prawdopodobieństwa wzięcia drugiego widelca, w przypadku nie wzięcia tego drugiego widelca opuszcza się widelec pierwszy)
- ustalenie priorytetów wyboru widelców (przy podnoszeniu najpierw wybiera się sztućce o numerach niższych, a przy oddawaniu najpierw oddaje się sztućce o numerach wyższych)
- rozwiązanie czystych i brudnych widelców
- ustawienie pierwszeństwa w jedzeniu dla filozofa o najmniejszej ilości skonsumowanych posiłków


Co prawda implementacja problemu 5 filozofów nie jest jeszcze gotowa, ale mogę wysunąć wnioski, że dużo przyjemniej rozwiązuje się ten problem w innych językach programowania - przynajmniej nie trzeba pracować na zmiennych globalnych czy na job'ach. Dużo przyjemniejsza była by implementacją tego problemu w C# niż w PS. PS jak na razie nie ma prostych sposobów synchronizacji job'ów. Taka prosta sprawa jak wyświetlanie komunikatów też nie była prosta. Write-Host nie wyświetla komunikatów w konsoli dopóki nie pobierze się job'a. Można było zawiesić komputer za pomocą symulację dla 20 filozofów i przetrzymując wszystkie komunikaty w pamięci. Nawet jak wyjdziemy z debuggera to job'y i tak będą wykonywać się.

Cały kod źródłowy można pobrać z github.

wtorek, 8 lipca 2014

Doping dla PowerShell ISE

Przeglądając polski blog o PowerShellu, natrafiłem na bardzo ciekawy wpis o dodatku do PowerShell ISE - ISESteroids. Od razu musiałem sprawdzić ten dodatek i muszę powiedzieć, że jestem bardzo miło zaskoczony. Tool można pobrać z tego linka, a tutaj jest art. o nim w PowerShell Magazine.

Bardzo polecam :)

niedziela, 6 lipca 2014

Sprawdzanie plików z datą

Jeżeli pracowałeś z źródłem danych w formie plików tworzonych każdego dnia, to za pewne miałeś problem ze sprawdzeniem czy są wszystkie pliki. Przesyłam proste skrypty sprawdzające takie pliki.
Na początku potrzebujemy funkcję do iteracji po dacie:
function Iterate-Date
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$True,Position=1)]
        [ValidateNotNull()]
        [DateTime]
        $startDate
        , 
        [Parameter(Mandatory=$True,Position=2)]
        [ValidateNotNull()]
        [DateTime]
        $endDate
    )

    for($i = $startDate; $i -le $endDate; $i = $i.AddDays(1))
    {
        $i
    }
}
Potrzebna będzie funkcja sprawdzająca czy istnieje nazwa pliku z podanym patternem:
function Test-FileName    
{
    param(
        [string]$path='.'
    )

    process{
        $filter= $_
        $items = gci -Path $path -Filter $filter 

        new-object PSObject | Add-Member -MemberType NoteProperty -Name Filter -Value $filter -PassThru | 
        Add-Member -MemberType NoteProperty -Name Items -Value $items -PassThru |
        Add-Member -MemberType NoteProperty -Name Contains -Value ([bool]$items) -PassThru
    }
}
Samo sprawdzanie czy istnieje plik z patternem yyyy-MM-dd* jest poniżej:
Iterate-Date -startDate ([DateTime]("2005-02-13")) ([DateTime]("2014-06-16")) | 
%{ $_.ToString('yyyy-MM-dd') + "*"} | group | %{$_.name} |
Test-FileName |
? {-not $_.Contains}
Aby uprościć powyższe wywołanie to możemy zamienić group za pomocą poniższej funkcji:
function Get-KeyGroupObject
{
    param(
        [string]
        $keyPropName = 'name'
    )
    #in variable  $input (enumerator type) we have all items
    $Input | group | %{$_.$keyPropName​} 
}
A sprawdzanie wygląda następująco:
Iterate-Date -startDate ([DateTime]("2005-02-13")) ([DateTime]("2014-06-16")) | 
%{ $_.ToString('yyyy') + "*"} | Get-KeyGroupObject |
Test-FileName |
? {-not $_.Contains}

piątek, 4 lipca 2014

Algorytmy geometryczne w PowerShell

Wystartowałem z kolejnym projektem w PS, tym razem z algorytmami geometrycznymi. Chciałbym zrobić framework oraz zaimplementować parę alg. geometrycznich. Dopiero co zacząłem implementację i dużo jeszcze jest przede mną.
Na samym początku można stworzyć punkt dla int jak i dla float:
new-p 1 2
new-pf 1.4 2.1

Aby funkcje zadziałały to należy uruchomić funkcje Init-GeoAlg znajdująca się w pliku PointsCommon.ps1.
Możesz wygenerować 100 punktów od punktu (0,0) do (100,100) wywołując:
Generate-PF -iterateNum 100

Lub za pomocą wyrażenia lambda (oficialnie nie ma w PS :) ) można podać scriptblock zwracający wartość równej sumy poprzedniej wartości i iteratora:
Generate-PF -iterateNum 100 -funcX {param($prevVal, $i) $i + $prevVal}

Jak na razie to nie wiele alg. zaimplementowałem (spr. czy punkt znajduje się na odcinku, sortowanie punktów po koncie nachylenia względem osi OX, znajdywanie parę punktów o najmnijszej odległości od siebie itd.).

Z pomocą pestera, zacząłęm pisać testy w stylu BDD, ale jak na razie nie wiem jak można weryfikować mocka na alias w pipelinie w wywołaniu rekurencyjnym. Tej funkcjonalności brakuje mi w pester.


Projekt można znaleźć na moim github. Pomysł na projekt o alg. geometrycznych powstał po prezentacji o tym temacie:


czwartek, 3 lipca 2014

Reaktywacja c++

Od wielu lat nie siedzę w c++, ale ostatnio obejrzałem filmik co ma do zaoferowania nowy C++14 i C++11. Jestem w głębokim szoku. Nowe featury pochodzą od takich popularnych języków jak java, c# czy python. Dawno temu uczyłem się c++, ale kiedy tylko natrafiłem na przejrzysty język c#, to od razu c++ poszedł w niepamięć. Myśłe, że dużo jest osób, którzy tak samo zrobili jak ja. Czy zacznie rosnąć popularność c++ ? Nie wiem.
Poniżej filmik o c++:




środa, 2 lipca 2014

Sprawdzenie wolnego obszaru na dysku


Tak często potrzebuje sprawdzać wolny obszar na dysku, że postanowiłem zamieścić ten krótki kod:
gwmi win32_logicaldisk | select DeviceID, @{n="FreeSpace (GB)"; e={$_.FreeSpace/1GB}},  @{n="Size (GB)"; e={$_.Size/1GB}}

Oprócz tej komendy chciałbym Ci przedstawić tool o nazwie WinDirStat. Oczywiście można pobrać ten tool z chocolatey.

Testy w PowerShell

Ostatnio zająłem się testowaniem skryptów PowerShell. Skorzystałem z narzędzia pester. Bardzo spodobał mi się ten tool.
Dla przykładu mamy funkcję do testowania, która dodaje metody do kastowania na int, double oraz byte
function Add-CastingFunctions($value) {
    return Add-Member -InputObject $value -Name ToInt `
           -MemberType ScriptMethod -PassThru -Force -Value `
           { [int] $this } |
           Add-Member -Name ToDouble `
           -MemberType ScriptMethod -PassThru -Force -Value `
           { [double] $this } |
           Add-Member -Name ToByte `
           -MemberType ScriptMethod -PassThru -Force -Value `
           { [byte] $this } 
}
Poniżej mamy test ( w osobnym pliku):
Describe "when added cast function to string '5'"  {
    $patched = Add-CastingFunctions("5")

    Context "and I do not attempt to cast it" {
        It "returns a string" {
            $patched.GetType().Name| Should be "string"
        }
    }

    Context "and I attempt to cast it as an integer" {
        It "returns a value that is of type integer" {
            $patched.ToInt().GetType().Name| Should be ("Int32")
        } 
    }

    Context "and I attempt to cast it as a double" {
        It "returns a value that is a double" {
            $patched.ToDouble().GetType().Name| Should be ("Double")
        }
    }

    Context "and I attempt to cast it as a byte" {
        It "returns a value that is a byte" {
            $patched.ToByte().GetType().Name| Should be ("Byte")
        }
    }
}

W tym samym pliku co jest test, musimy dodać nagłówek:
$pwd = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests", "")
. "$pwd\$sut"
Niestety, trzeba w każdym pliku dodawać ten sam nagłówek, więc wpadłem na pomysł, aby dodać ten nagłówek do snippeta.
New-IseSnippet -Title 'pester-header' -Description  'Adds pester header' -Text '
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".")
. "$here\$sut" 
' -Force
Teraz, dzięki temu snippetowi możesz w PS_ISE dodać nagłówek za pomocą CTRL + J