środa, 27 kwietnia 2016

Restartowanie kart sieciowych w Powershell'u

Czasem karty wifi potrafią być włączone, ale przestają się łączyć do widocznych sieci. Często dzieje się tak przy używaniu hibernacji w laptopach. Być może wina leży w źle napisanych sterownikach lub innych własnościach sprzętu. Można łatwo sobie z tym poradzić stosując prosty skrypt w Powershell'u:

Skrypt działa najlepiej, gdy będzie odpalony z prawami administratora.

środa, 20 kwietnia 2016

Podstawowe błędy w programowaniu (początkujących)

1. Indeksowanie

Zasadnicze pytanie: indeksujemy od 0 czy 1? Pierwszy element ma indeks 0 czy 1? Problem który dotyka niektórych początkujących uczących się nowego języka, szczególnie gdy pierwszym z nich był taki, który obsługiwał indeksowanie tablic bardziej "matematycznie", formalnie czyli pierwszy element w tablicy miał indeks 1. Może to prowadzić do szeregu błędów w stylu "off by one".

int n = 10;
int[] tabs = new int[n];
for (int i=1; i<=n; i++)
{
 tabs[i] = i+1;
}

W powyższym przypadku popełniono dwa błędy: pierwszy polega na pominięciu pierwszego elementu (o indeksie zero i rozpoczęciu indeksowania od 1). Drugi błąd to wyjście poza granice tablicy (IndexOutOfRangeException) przez źle skonstruowany warunek wykonania pętli.

2. Wyrażenia warunkowe

Początkujący programiści dosyć często zachłystują się możliwościami jakie daje instrukcja if. Są w stanie "zaprogramować" rozmaite działania programu bazując jedynie na tej instrukcji (oraz instrukcji switch..case gdy ją poznają) poprzez budowanie rozległych łańcuchów if..else..if..else.

int e = 2;
//...
if (e==0)
{
 Console.Write("Brak danych");
}
else if (e==1)
{
 Console.Write("Błędne dane");
}
else if (e==2)
{
 Console.Write("Inny problem");
}

W takim przypadku warto rozważyć inne podejście i zaprogramować bardziej czytelne, i skuteczne rozwiązanie.

int e = 2;
//...
string[] errors = new string[] { "Brak danych", "Błędne dane", "Inny problem" };
Console.WriteLine(errors[e]);

3. Wyrażenia logiczne

Logika boolowska to podstawa w formułowaniu działania programu. Opierają się na niej wspomniane wcześniej wyrażenia warunkowe. Budowanie takich wyrażeń musi być zawsze przemyślane, gdyż nieodpowienio zbudowane wyrażenia mogą być przyczyną błędów, a nawet mieć wpływ na wydajność.

W przypadku zastosowania operatorów logicznych && i || ważna jest kolejność operandów. W przypadku sumy logicznej, gdy pierwszy z nich jest false to zaniechane jest dalsze przetwarzanie wyrażenia. W przypadku alternatywy, takie zaniechanie następuje gdy pierwszy z operandów jest true.

Skrócone przetwarzanie wyrażeń logicznych zyskuje na znaczeniu gdy, przewidujemy która część wyrażenia będzie powodowała skrócenie przetwarzania wyrażenia.

4. Operatory as i is oraz rzutowanie

Rzutowanie typów w C# można przeprowadzić na dwa sposoby. Podając nazwę typu w nawiasie przed odwołaniem do obiektu (Control)zmienna; lub przy pomocy operatora as zmienna as Control.

W pierwszym przypadku gdy rzutowanie nie jest możliwe, zostanie wyrzucony wyjątek, w drugim przypadku otrzymamy null. Rzutowanie przez operator as można stosować tylko dla typów referencyjnych i zerowalnych (Nullable<>).

W większości przypadków, wyjątków związanych z nieprawidłowym rzutowaniem typów można uniknąć przez stosowanie operatora is. Operator ten zwraca true jeżeli sprawdzana zmienna jest typem podanym z prawej strony operatora, false w przeciwnym wypadku.

if (zmienna is Control)
{
   zmienna2 = (Control)zmienna;
}

5. Konkatenacja string'ów

Nieznajomość klas i metod z frameworka może być przyczyną powstawania problemów wydajnościowych. W tym przypadku nieodpowiednie

string[] animals = { "kot", "pies", "mysz" };

string allAnimals = string.Empty;

foreach (string s in animals)
{
    allAnimals += s + ", ";
}

Console.Write(allAnimals);

Powyższy kod jest bardzo nieefektywny pod kątem wykorzystania pamięci. Łącząc elementy z tabeli animals w pętli foreach, na każdą iterację przypadają aż trzy alokacje pamięci dla nowych ciągów znakowych. String jest typem, którego rozmiar jest ustalany w momencie przypisania. W momencie przypisywania nowego ciągu znaków do zmiennej tego typu, następuje powstanie nowego obiektu klasy string. Przy dużej ilości iteracji kod taki staje się problematyczny, bo zaczyna mocno obciążać zasoby przez ciągłe alokacje pamięci, oraz zmusza Garbage Collector do częstszego porządkowania pamięci - co ma wpływ na wydajność.

Kod poniżej działa prawie tak samo, ale znacznie efektywniej. Wykorzystuje wbudowaną metodę Join(), która jest zoptymalizowana do wykonania tego zadania. Wewnętrznie sama alokuje odpowiednią ilość pamięci dla łączonych ciągów.

string[] animals = { "kot", "pies", "mysz" };

string allAnimals = string.Join(", ", animals);

Console.Write(allAnimals);

wtorek, 8 marca 2016

Digispark Attiny85 - szybki start

Czym jest Digispark? To miniaturowa płytka z mikrokontrolerem Attiny85 oparta o ideę Arduino. Czyli korzystamy z IDE Arduino i niektórych bibliotek. Dlaczego niektórych? A dlatego, że nie wszystko się zmieści łącznie z programem w pamięci mikrokontrolera Attiny85 - 8kB, która to pamięć jest jeszcze zmniejszona o 2kB przez bootloader. Więc dużo nie zostaje. Dokładna specyfikacja. Układ można zasilać wprost z portu USB, lub przez odpowiednie piny na płytce. Przez to, że mikrokontroler jest wpięty wprost do portu USB, należy uważać by nie uszkodzić portu w komputerze przez zwarcie w budowanym na bazie płytki układzie. Producent poleca podpinać płytkę przez hub USB, lub uruchamiać korzystając z zewnętrznego zasilacza.

Jak zacząć

1. Sterowniki

Pobieramy sterowniki - można pobrać plik _DriverFiles.7z lub pobrać całe repozytorium.
Może się zdarzyć, że system po zainstalowaniu nie widzi płytki (pojawia się nieznane urządzenie). Wtedy należy ręcznie wskazać sterowniki do płytki w menedżerze urządzeń:
  1. Klikamy prawym klawiszem myszy na "Nieznane urządzenie";
  2. W zakładce "Sterownik" wybieramy "aktualizuj sterownik";
  3. Potem "Przeglądaj mój komputer w poszukiwaniu oprogramowania sterownika";
  4. Następnie "Pozwól mi wybrać z listy sterowników urządzeń na moim komputerze";
  5. Na następnym ekranie wybieramy pozycję "Pokaż wszystkie urządzenia" i dajemy dalej;
  6. W kolejnym oknie klikamy przycisk "Z dysku" i w oknie dialogowym wyboru plików wybieramy plik inf w katalogu ze sterownikami do Digisparka;
  7. Akceptujemy to że sterownik nie jest podpisany cyfrowo;
  8. Po zainstalowaniu sterownika, odłączamy na chwilę płytkę od portu i po ponownym włączeniu powinna być już widoczna jako "Digispark USB".
W moim przypadku urządzenie stało się wykrywalne po bezpośrednim wpięciu do portu USB komputera, wpięcie przez hub powoduje, że płytka nie jest wykrywana.

2. IDE Arduino

W Arduino IDE dodajemy nowe źródło konfiguracji płytek http://digistump.com/package_digistump_index.json:

Później w "Menedżerze płytek" instalujemy "Digistump AVR Boards"

3. Wgrywamy pierwszy program

W porównaniu do klasycznego Arduino, program wgrywa się w momencie wpięcia płytki do portu USB. Bootloader przez około 5 sekund oczekuje na zaprogramowanie. Dlatego najpierw w Arduino uruchamia się załadowanie szkicu, a dopiero pod koniec po komunikacie, mówiąc o wpięciu płytki wpina się ją (zazwyczaj jest na to przeznaczone 60 sekund) i następuje rzeczywiste załadowanie programu.
Na początek trzeba wybrać odpowiednią płytkę:

Później kompilujemy i ładujemy szkic do płytki (płytka musi być odłączona) i czekamy na komunikat:
W tym momencie podłączamy płytkę i po jej wykryciu nastąpi załadowanie szkicu:
Gotowe! Pierwszy szkic załadowany.

Podsumowanie

Płytka jest niewielka, szkice które można załadować też muszą być niewielkie. W porównaniu do Arduino, oferuje znacznie mniejsze możliwości. Plusem płytki są małe wymiary. Minusem jednak problematyczne działanie z USB. Samo ładowanie szkiców nie jest aż takim dużym problemem, można się przyzwyczaić, że najpierw szkic trzeba skompilować a potem podłączyć płytkę aby się załadował. Większym problemem jest wykrywanie urządzenia USB, sterowniki oraz huby USB, które nie zawsze chcą współpracować.

Mimo tego płytka Digispark może być ciekawą podstawą do projektów. Dołączone liczne przykłady pokazują różne zastosowania płytki. Mimo niewielkiej ilości pinów, można sobie poradzić budując projekty oparte o magistralę I2C.

Moim skromnym zdaniem to coś więcej niż tylko ciekawostka.

czwartek, 27 grudnia 2012

Łączenie URL-i jak Path.Combine()

Pracując z aplikacjami webowymi dosyć często zachodzi potrzeba połączenia dwóch stringów będących URL-ami. Można to zrobić w bardzo prosty sposób jak zwykłe łączenie dwóch stringów, przy pomocy plusa. Jednak to rozwiązanie jest nieeleganckie i może być źródłem nieoczekiwanych problemów.

Z drugiej strony w przypadku operowania na stringach będących ścieżkami na dysku możemy skorzystać z metody Path.Combine(), która bezpiecznie łączy dwa ciągi znaków. Dodając lub nie "\" w miejscu ich łączenia.

W przypadku łączenia URL-i nie mamy gotowej metody w frameworku, która działała by w taki sam sposób jak Path.Combine(). Można tu wykorzystać naturalną możliwość łączenia jaką daje konstruktor klasy Uri() jednak jego działanie nie będzie zgodne z oczekiwaniem. Dodatkowym problemem jest to, że nie można podać łączonych URL-i jako stringów.
string urlA = "http://example.org/info";
string urlB = "test.html";

Uri baseUri = new Uri(urlA);
Uri pathUri = new Uri(urlB, UriKind.Relative);
Console.Write(new Uri(baseUri, pathUri).ToString());

Wynikiem działania powyższego kodu będzie adres w postaci: http://example.org/test.html. Nie taki był zamiar, bo zgodnie z oczekiwaniem adres miał wyglądać tak: http://example.org/info/test.html aby zachować zachowanie takie jak Path.Combine().
Gdy lekko zmodyfikujemy łączone adresy:
string urlA = "http://example.org/info/";
string urlB = "test.html";

To otrzymamy właściwy adres zgodnie z oczekiwaniem. A co gdy dołączana część adresu będzie się zaczynać od "/"?
string urlA = "http://example.org/info/";
string urlB = "/test.html";

Otrzymamy znowu adres: http://example.org/info.html, więc wróciliśmy do punktu wyjścia. Kilka spostrzeżeń:
  • Pierwsza część adresu musi zawsze kończyć się znakiem "/"
  • druga część adresu nie może się zaczynać od znaku "/"
Zastosujmy więc poniższe wnioski do początkowego kodu:
string urlA = "http://example.org/info/";
string urlB = "/test.html";

Uri baseUri = new Uri((urlA.EndsWith("/") ? urlA : urlA + '/'));
Uri pathUri = new Uri(urlB.TrimStart('/'), UriKind.Relative);
Console.Write(new Uri(baseUri, pathUri).ToString());
Lub w bardziej przyjaznej formie metody:
public static string UrlCombine(string urlA, string urlB)
{
   // dodajmy / na końcu gdy go nie ma
   Uri baseUri = new Uri((urlA.EndsWith("/") ? urlA : urlA + '/'));
   // zawsze usuwamy znak / z początku
   Uri pathUri = new Uri(urlB.TrimStart('/'), UriKind.Relative); 
   return new Uri(baseUri, pathUri).ToString();
}

Omijając kilka właściwości klasy Uri udało się stworzyć metodę, która może ułatwić i przyspieszyć prozaiczną czynność jak łączenie adresów.

piątek, 4 maja 2012

HTML5: Element progress - pasek postępu

Standard HTML5 wprowadza kilka elementów, bardziej związanych z aplikacjami niż z typowymi dokumentami tekstowymi. Jednym z nich jest pasek postępu, który pozwala na graficzną reprezentację postępu czasochłonnej czynności, jak ściąganie/wysyłanie plików, przetwarzanie danych przez algorytm. Umieszczenie elementu w dokumencie:

<progress max="100"></progress>

Parametry:
  • max - wartość maksymalna,
  • value - aktualna wartość wskazywana przez pasek,
  • form - formularz do którego przypisany jest pasek.
Dostęp do paska postępu w JavaScript

<progress id="test" max="100"></progress>

Kod w JavaScript:

bar = document.getElementById("test");
bar.value = 50; // 50% postępu



W przypadku nieokreślenia parametru max pasek postępu, przyjmuje postać, w której nie wskazuje na aktualny postęp tylko pracę w toku (przesuwający się prostokąt).



Określanie wyglądu paska

Określenie tła i obramowania wygląda tak samo jak w innych elementach HTML. Problemem może być tu określenie koloru wskazującego na postęp. Nie można tego dokonać żadnym standardowym parametrem CSS.
Należy użyć pseudostyli dla konkretnej przeglądarki, w tym przypadku dla Firefoksa i Chrome:

progress::-webkit-progress-bar-value, 
progress::-webkit-progress-value,
progress::-moz-progress-bar {background-color: Red;}

wtorek, 13 września 2011

Dzień programisty 2011


  1. Uruchamiamy Visual Studio

  2. Tworzymy nowy projekt "Console Application"

  3. Wklejamy poniższy tekst

    using System;
    using System.Text;

    namespace Quine2011
    {
    class Program
    {
    const string q = "dXNpbmcgU3lzdGVtOw0KdXNpbmcgU3lzdGVtLlRleHQ7DQoNCm5hbWVzcGFjZSBRdWluZTIwMTENCnsNCiAgICBjbGFzcyBQcm9ncmFtDQogICAgew0KICAgICAgICBjb25zdCBzdHJpbmcgcSA9ICIyNTYiOw0KICAgICAgICBzdGF0aWMgdm9pZCBNYWluKHN0cmluZ1tdIGFyZ3MpDQogICAgICAgIHsNCiAgICAgICAgICAgIGNvbnN0IHN0cmluZyB4MjU2ID0gIjI1NiI7DQogICAgICAgICAgICBzdHJpbmcgdiA9IEVuY29kaW5nLkRlZmF1bHQuR2V0U3RyaW5nKENvbnZlcnQuRnJvbUJhc2U2NFN0cmluZyhxKSk7DQogICAgICAgICAgICBpbnQgcCA9IHYuSW5kZXhPZih4MjU2KTsNCiAgICAgICAgICAgIENvbnNvbGUuV3JpdGUodi5TdWJzdHJpbmcoMCwgcCkgDQogICAgICAgICAgICAgICAgKyBxIA0KICAgICAgICAgICAgICAgICsgdi5TdWJzdHJpbmcocCArIHgyNTYuTGVuZ3RoKSk7DQogICAgICAgICAgICBDb25zb2xlLlJlYWRLZXkoKTsNCiAgICAgICAgfQ0KICAgIH0NCn0NCg==";
    static void Main(string[] args)
    {
    const string x256 = "256";
    string v = Encoding.Default.GetString(Convert.FromBase64String(q));
    int p = v.IndexOf(x256);
    Console.Write(v.Substring(0, p)
    + q
    + v.Substring(p + x256.Length));
    Console.ReadKey();
    }
    }
    }



  4. Kompilujemy i uruchamiamy

  5. Do zobaczenia za rok

czwartek, 19 maja 2011

dotPeek - nowy dekompilator dla .NET

Po tym jak okazało się, że Reflector nie będzie już dostępny w najprostszej wersji jako darmowe oprogramowanie, wielu programistów zaczęło prace nad odpowiednikiem. Pierwszym takim rozwiązaniem jest ILSpy, o którym niedawno pisałem.

Mimo tego ludzie z JetBrains (autorzy dodatku do Visual Studio - ReSharper) rozpoczęli prace nad swoją aplikacją.



Obecna wersja programu dostępna pod adresem:
http://www.jetbrains.com/decompiler/

Wersja ta jest jeszcze niestabilna. Gdy uruchamiałem pierwszy raz dotPeek, program zawiesił się po czym pojawiła się propozycja wysłania raportu o błędzie do autorów. Jest to normalne zachowanie programu, który znajduje się we wczesnym stadium tworzenia. Wygląd programu przypomina Visual Studio i zapewne dotPeek będzie elementem kolejnej wersji ReSharpera. Reszta opcji jest znana z Reflectora, może poza możliwością otwarcia modułów z GAC - w Reflectorze trzeba było najpierw znaleźć odpowiedni plik i dopiero go otworzyć, co nie zawsze było proste i wygodne.

Wczesna wersja dostępna jest w wersji darmowej (EAP -Early Access Program).