18 listopada 2016

[VPython] Siła sprężystości

Dwie symulacje, właściwie bliźniacze, w których prezentowane jest działanie siły sprężystości (bez tłumienia). Każdy układ ma inną stałą sprężystości i położenie początkowe, dlatego zachowują się inaczej. W pierwszym przykładzie na układ działa dodatkowo siła grawitacji


W drugim przykładzie mamy ciało poruszające się na sprężynie horyzontalnie bez poślizgu. Nie jest rozważana siła grawitacja, która i tak by była równoważona przez oddziaływanie podłoża.

1 listopada 2016

paramiko/rforward.py i py2exe

Dobrze jest mieć w zanadrzu mechanizm pozwalający na uruchomienie pythonowego skryptu na systemie pozbawiony interpretera. Do celów testowych wybrałem rforward.py, który pozwala na stworzenie tunelowanego połączenia, pochodzący z biblioteki Paramiko. Wydaje się, że biblioteka jest całkiem rozbudowana, więc może być dobrym polem do testów. Zestaw linków:
Instalacja pakietów dla Paramiko i py2exe:
c:\Python34\Scripts>pip install cryptography
c:\Python34\Scripts>pip install pycrypto
c:\Python34\Scripts>pip install paramiko

c:\Python34\Scripts>pip install py2exe
Domyślny pip dostarczony wraz z interpreterem miał kłopot, aby zainstalować niektóre pakiety. Okazało się, że aktualizacja do najnowszej wersji rozwiązuje problem.
You are using pip version 7.1.2, however version 8.1.2 is available.
You should consider upgrading via the 'python -m pip install --upgrade pip' command.
Problemem okazała się również wersja pythona, której używałem. py2exe działa do wersji 3.4. Wersji 3.5 towarzyszą jakieś zawirowania i trzeba będzie na nią jeszcze poczekać.
Building 'dist\rforward.exe'.
error: [Errno 2] No such file or directory: 'c:\\Python35\\lib\\site-packages\\py2exe\\run-py3.5-win-amd64.exe'
Aby stworzyć plik wykonywalny należy stworzyć skrypt setup.py, w którym wyszczególnimy z jakich plików składa się nasz program.
from distutils.core import setup
import py2exe
from glob import glob

setup(console=['rforward.py'],
      data_files = [('', ['C:\\Windows\\System32\\msvcr100.dll',
                          'C:\\Windows\\System32\\msvcp100.dll'])])
To czego może zabraknąć na docelowej maszynie, to biblioteki z Visual Studio 2010, których wymaga do działania python. Można je również zainstalować za pomocą Microsoft Visual C++ 2010 Redistributable Package (x86). Ja wybrałem wersję na 32-bitową, zgodną z zainstalowanym interpreterem. Tutorial py2exe (dla starszej wersji pythona), ostrzega o restrykcjach odnośnie kopiowania tych bibliotek, a mianowicie powinno kopiować się wszystkie trzy, a nie tylko wybraną oraz manifest. Pozostawię to jako kwestię otwartą, ponieważ, nie mogłem znaleźć tego w dokumentacji, ponadto jeden z plików (msvcp100.dll), gdzieś wyparował. Z tego co wiem do działania wymagany jest jedynie msvcr100.dll (nie testowałem). Pliki należy skopiować, do głównego katalogu, tak, by exe mógł je odnaleźć.
Aby zbudować plik wykonywalny wystarczy wywołać setup.py z opcją py2exe. Całość potrzebna do działania programu powinna znaleźć się w katalogu dist.
c:\Python34\python.exe setup.py py2exe

23 października 2016

Windows 7 update ...

Jak wymusić aktualizację sytemu (Windows 7) po świeżej instalacji. Mechanizm nie informuje o postępie poszukiwań i można czekać na to kilka dni. Ratunkiem są dwa patche, (może będą kolejne, bo co jakiś czas przestaje działać): KB3102810, KB3172605.

Warto sprawdzić, czy są one już obecne w systemie, a przed dokonaniem aktualizacji najlepiej wyłączyć usługę odpowiedzialną za aktualizację (Start | services.msc | "Windows Update | Stop) i włączyć ją ponownie po:
PS C:\Users\beru> get-hotfix -id KB3102810
PS C:\Users\beru> get-hotfix -id KB3172605

20 października 2016

[python] Prosty skrypt z uruchomieniem wątku.

Jak mówi Internet CPython w związku z istnieniem mechanizmu Global Interpreter Lock (GIL) nie pozwala na wykonanie więcej niż jednego wątku:
CPython implementation detail: In CPython, due to the Global Interpreter Lock, only one thread can execute Python code at once (even though certain performance-oriented libraries might overcome this limitation). If you want your application to make better use of the computational resources of multi-core machines, you are advised to use multiprocessing or concurrent.futures.ProcessPoolExecutor. However, threading is still an appropriate model if you want to run multiple I/O-bound tasks simultaneously.
Niemniej jednak Python posiada stosowne API, które da się wykorzystać w innym interpreterze bez ograniczeń GIL, albo przy zadaniach typu I/O.

Queue (kolejka) zapewnia bezpieczny mechanizm do wymiany informacji pomiędzy wątkami.
  • Każde zawołanie Queue.put() zwiększa licznik, który jest dekrementowany w momencie zawołania Queue.task_done().
  • Główny wątek jest blokowany przez Queue.join(), do momentu, gdy wszystkie elementy z kolejki zostaną przetworzone.
  • Funkcja Queue.get() jest domyślnie blokująca, tzn. wątek zawiesza działania, jeżeli nie ma już danych do przetworzenia.
  • Thread.daemon - wszystkie wątki potomne zostaną zabite wraz z wątkiem głównym.
Często po wywołaniu programu na konsoli pojawia się informacja o wystąpieniu wyjątku. Jest to związane ustawieniem daemon=true. Interpreter nie zdążył z czystym zamknięciem wątku gdy kończony jest wątek główny. Rozwiązaniem byłby mechanizm w samum wątku, pozwalający na jego zakończenie, gdy nie jest on już potrzebny. W przypadku prostych skryptów, raczej nie trzeba się tym przejmować.
# -*- coding: utf-8 -*-

from Queue import Queue
from threading import Thread, current_thread

def worker():
    while True:
        item = q.get()
        print current_thread().name + ': ' + str(item[0] + item[1])
        q.task_done()

q = Queue()
num_worker_threads = 3

for i in range(num_worker_threads):
    t = Thread(target=worker)
    t.daemon = True
    t.start()

for item in [(1, 2), (4, 7), (5, 2)]:
    q.put(item)

q.join()
Wynik:
Thread-2: 3
Thread-2: 11
Thread-3: 7

15 października 2016

pdfunite - łączenie kilku dokumentów w jeden

Magiczny zlepek komend do połączenia kilku pdf-ów w jeden.
ls -v *.pdf | bash -c 'IFS=$'"'"'\n'"'"' read -d "" -ra x; pdfunite "${x[@]}" output.pdf'

26 lipca 2016

[Chemia] Białka

Dwie interesujące prezentacje na temat białek.
Wyjaśnienie czym są białka i jak są zbudowane. Paul Andersen "Proteins":



O człowieku, który buduje własne białka (z wykorzystaniem Lisp-a i LLVM) i chce budować jeszcze, oraz dlaczego C++ się do tego nie nadaje. Christian Schafmeister "Clasp: Common Lisp using LLVM and C++ for Molecular Metaprogramming":


23 lipca 2016

gdb + python

Bardzo łagodne wprowadzenie do tematyki użycia pythona w gdb i jeszcze raz na podstawie CppCon 2015: Greg Law "Give me 15 minutes & I'll change your view of GDB"
Na początku jednak kilka komend, które okazały się całkiem pomoce w procesie nauki:
  • start - ustawia się na pierwszej instrukcji naszego programu, w zależności od systemu punkt wejścia może mieć różną nazwę, gdb w takim przypadku zachowa się uniwersalnie.
  • save breakpoints mybbb - zapisanie breakpointów do pliku. Przydatne, gdy trzeba zamknąć gdb, ale nie chcemy niszczyć dorobku naszej sesji.
  • source mybbb - załadowanie breakpointów z pliku
Proste wykorzystanie pythona, do odczytania process id. Aby zakończyć interaktywny tryb należy wpisać end, podobnie jak to się dzieje w przypadku command.
(gdb) python
>import os
>print('pid %d' % os.getpid())
>end
pid 17865
Odczyt informacji o breakpointach:
Reading symbols from a.out...done.
(gdb) b 8
Breakpoint 1 at 0x400589: file main.cpp, line 8.
(gdb) info break
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000400589 in main() at main.cpp:8
(gdb) r
Starting program: /home/user/cpp_gdb_test/a.out 
is i now 7

Breakpoint 1, main () at main.cpp:8
8     i++;
(gdb) python
>print(gdb.breakpoints()[0].location)
>end
/home/user/cpp_gdb_test/main.cpp:8
Ustawienie braekpointa z poziomu pythona:
(gdb) python gdb.Breakpoint('11')
Breakpoint 2 at 0x4005a1: file main.cpp, line 11.
(gdb) c
Continuing.
is i now 8

Breakpoint 2, main () at main.cpp:11
11     printf("Hello world!!!\n");

22 lipca 2016

[CppCon 2015] recording w gdb

Fajny lightning talk na zeszłorocznej konferencji CppCon 2015 traktujący o przydatnych trikach w procesie debugowania programu:



Postanowiłem przećwiczyć sobie kilka mechanizmów. Najciekawszą rzeczą dla mnie był record, który umożliwia odtworzenie wartości pamięci przy reverse debug-u. Szczególnie przydatny, gdy program pisze po stosie i nie można odtworzyć pechowej sekwencji instrukcji z core dumpa. Linki:
Przykładowy program, który w chwili, gdy zostanie wylosowana wartość 4, dla zmiennej v, zaczyna pisać po stosie.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void overflow(int v)
{
    char t[10];

    if (v == 4)
    {
        for (int n = 0; n < 10000; n++)
            t[n] = 'A';
    }
}

int main()
{
    srand(time(0));

    int i;
    do
    {
        i = rand() % 10;
        printf("i is now %d\n", i);
        int v = rand() % 100;
        overflow(v);
    } while(i != 5);

    return 0;
}

Kompilacja, konfiguracja i uruchomienie, trzeba pamiętać o ustawieniu rozmiaru ulimit dla core dump-ów, domyślnie jest to bowiem wartość 0.
ulimit -a 
ulimit -c unlimited 
ulimit -a 

gcc -g main.cpp
while ./a.out ; do echo "OK"; done
gdb a.out -c core
Wynik:
i is now 3
i is now 2
Segmentation fault (core dumped)
Stos został uszkodzony, w tym przypadku widać ślad po ostatniej instrukcji i z jaką wartością została wykonana, ale w przypadku bardziej skomplikowanych struktur danych, może być to kłopotliwe.
Core was generated by `AAAAAAAA'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  __GI_getenv (name=0x7f15a332b3c2 "BC_FATAL_STDERR_", name@entry=0x7f15a332b3c0 "LIBC_FATAL_STDERR_") at getenv.c:84
84  getenv.c: No such file or directory.
(gdb) p i
No symbol "i" in current context.
(gdb) p v
No symbol "v" in current context.
(gdb) p t
No symbol "t" in current context.
(gdb) bt
#0  __GI_getenv (name=0x7f15a332b3c2 "BC_FATAL_STDERR_", name@entry=0x7f15a332b3c0 "LIBC_FATAL_STDERR_") at getenv.c:84
#1  0x00007f15a31d7ef2 in __GI___libc_secure_getenv (name=name@entry=0x7f15a332b3c0 "LIBC_FATAL_STDERR_")
    at secure-getenv.c:29
#2  0x00007f15a321549a in __libc_message (do_abort=do_abort@entry=1, 
    fmt=fmt@entry=0x7f15a332cc7f "*** %s ***: %s terminated\n") at ../sysdeps/posix/libc_fatal.c:80
#3  0x00007f15a32b689c in __GI___fortify_fail (msg=<optimized out>, msg@entry=0x7f15a332cc61 "stack smashing detected")
    at fortify_fail.c:37
#4  0x00007f15a32b6840 in __stack_chk_fail () at stack_chk_fail.c:28
#5  0x00000000004006bb in overflow (v=4) at main.cpp:14
#6  0x4141414141414141 in ?? ()
#7  0x4141414141414141 in ?? ()
Próba odtworzenia problemu z wykorzystaniem record. gdb przechowa zawartość pamięci, z kolejnych kroków wykonania programu, dzięki czemu można się cofnąć, o jedną komendę (reverse-next), na sam początek nagrywania (reverse-continue), lub skorzystać z innych bliźniaczych komend (reverse-*).

Inne udogodnienia, z których skorzystałem to warunkowy breakpoint w linii 3 (b 26 if v == 4), który zachodzi, gdy zmienna v będzie miała ustawioną wartość na 4. Oraz command, który zostaje wykonany w momencie zatrzymania programu (linie 12-17). Pierwszym argumentem command jest numer porządkowy breakpoint-a, który można uzyskać z info break.
gdb a.out

(gdb) b 26 if v == 4
Breakpoint 1 at 0x400748: file main.cpp, line 26.
(gdb) b 11
Breakpoint 2 at 0x400686: file main.cpp, line 11.
(gdb) info break
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000400748 in main() at main.cpp:26
 stop only if v == 4
2       breakpoint     keep y   0x0000000000400686 in overflow(int) at main.cpp:11
(gdb) command 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>record
>continue
>end
(gdb) r
Starting program: /home/user/cpp_gdb_test/a.out 
i is now 9
i is now 7
i is now 2
i is now 3
i is now 3
i is now 9
i is now 9

Breakpoint 1, main () at main.cpp:26
26         overflow(v);

Breakpoint 2, overflow (v=4) at main.cpp:11
11         for (int n = 0; n < 10000; n++)
(gdb) 
(gdb) bt
#0  overflow (v=4) at main.cpp:11
#1  0x0000000000400752 in main () at main.cpp:26
(gdb) reverse-next
9     if (v == 4)
(gdb) 
6 {
(gdb) 

No more reverse-execution history.
main () at main.cpp:26
26         overflow(v);
(gdb) p i
$5 = 9

11 lipca 2016

Gif-y w wysokiej jakości

Znakomity wpis na temat uzysykiwania gif-ów wysokiej jakości:
Moja stara wersja korzystała ze zbyt wielu kroków. W dodatku nie mogłem zmusić programu convert do ustawienia mniejszego opóźnienia pomiędzy ramkami niż 10. W przykładzie poniżej zrezygnowałem ze skalowania.
ffmpeg -i video.avi -r 10 -f image2pipe -vcodec ppm - | convert -delay 10 -loop 0 - gif:- | convert -layers Optimize - output.gif
Lepsza wersja (także bez skalowania). Kroków jest na tyle dużo, że zamknąłem wszystko w jednym skrypcie, ale convert nie jest już wykorzystywany, ponieważ sam ffmpeg dobrze sobie radzi z tworzeniem plików tego formatu:
#!/bin/sh

palette="palette.png"
video="video.avi"

# filters="fps=15,scale=320:-1:flags=lanczos"
filters="fps=25"

mogrify -crop 384x362+8+30 +repage $(ls -v *.png)
ffmpeg -r 100 -f image2 -i img-%3d.png $video
ffmpeg -v warning -i $video -vf "$filters,palettegen" -y $palette
ffmpeg -v warning -i $video -i $palette -lavfi "$filters [x]; [x][1:v] paletteuse" -y output.gif
Obraz jest znacznie płynniejszy.

2 lipca 2016

goto criticism

Przez lata przyjmowałem za pewnik słowa, że "nie należy korzystać z goto" i tak właściwie, to nie pamiętam, żebym to kiedyś zrobił, ba nawet nie miałem okazji widzieć takiego kodu zbyt często. Takie też jest moje wewnętrzne przekonanie. Program korzystający z takiego wyrażenia, nie byłby przyjemny w utrzymaniu. Właściwie więc, po co te mechanizmy w językach nadal istnieją? Wyjątkiem kodu, który miałem okazję analizować były funkcje kryptograficzne, których działanie było zawiłe samo w sobie. Postanowiłem jednak sięgnąć do źródeł całego trendu. I tutaj, nie jest już tak czarno-biało. Ze spostrzeżeń Edsgera Dijkstry ("za") i Donalda Knutha ("przeciw") stworzono dogmat, a sami autorzy zgadzają się, że dla pewnych problemów optymalizacyjnych skorzystanie z goto jest konieczne, chociaż w większości przypadków będzie to symptom źle zaprojektowanego kodu. Odbiegając od specyficznych przypadków dotyczących małej części całej aplikacji, sam Knuth miał jednak nadzieję, że powstaną w przyszłości mechanizmy umożliwiające tłumaczenie wysokopoziomowego kodu, na niskopoziomowy, bez wymogu korzystania z tego wyrażenia. Po 40 latach kompilatory już całkiem nieźle sobie radzą, ale to jeszcze kiedyś sprawdzę.

26 czerwca 2016

Rachunek wektorowy i książki

Kilka przydatnych książek, które znalazłem na wikibooks, ucząc się fizyki. Niektórym brakuje rozdziałów, ale i tak jestem pod wrażeniem. Warto się temu przyjrzeć, jako coś dodatkowego do klasycznych podręczników:
Coś z rachunku wektorowego - wirujący wektor, do którego stworzenia potrzebna jest macierz obrotu [1], [2].
Program koduj macierze przekształceń właściwą dla dwóch wymiarów:
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from visual import *
import ImageGrab

display(x=0, y=0, width=400, height=400, userzoom=False,
        center=(0, 0, 1), foreground=(0, 0, 0), background=(1, 1, 1))

ar = arrow(pos=(0, 0, 0), axis=(10, 0, 0), shaftwidth=0.3)

total_angle = 0
angle = 0.1 / (2 * math.pi)
frame = 0
while total_angle <= 2 * math.pi:
    rate(100)

    nx = ar.axis.x * math.cos(angle) - ar.axis.y * math.sin(angle)
    ny = ar.axis.x * math.sin(angle) + ar.axis.y * math.cos(angle)
    nz = 0
    ar.axis = (nx, ny, nz)

    file_name = 'img-' + '{fr:03d}'.format(fr=frame) + '.png'
    frame += 1

    im = ImageGrab.grab((0, 0, 400, 400))
    im.save(file_name)

    total_angle += angle
    print total_angle

exit()

24 czerwca 2016

[python] matplotlib - rysowanie wykresów

Kolejna biblioteka, którą zacząłem się bawić, służąca do rysowania wykresów: matplotlib. Bardzo przyjema dokumentacja, z dużą liczbą przykładów. Dla testu wykreśliłem pochodną i całkę oznaczoną dla funkcji:
$$ f(x) = -2x^{3} - 4x^{2} + 8x + 1 \\
f^\prime(x) = -6x^{2} - 8x + 8 \\
F(x) = \int f(x) dx = -\frac{1}{2}x^{4} - \frac{4}{3}x^{3} + 4x^{2} + x + C \\
F(-3) - F(1) = \int_{-3}^{1} f(x) dx = \left(-\frac{1}{2}x^{4} - \frac{4}{3}x^{3} + 4x^{2} + x + C\right)\Biggr|_{-3}^{1} $$
Kod programu:
#!/usr/bin/env python
# -*- coding: utf-8 -*-


import numpy as np
import matplotlib.patches as mpatches
import matplotlib.pyplot as plt


def main():
    red_patch = mpatches.Patch(color='red', label=r'$f(x)$ - moja funkcja')
    blue_patch = mpatches.Patch(color='blue', label=r'$f^\prime(x)$ - obliczone numerycznie')
    cyan_patch = mpatches.Patch(color='cyan', label=r'$f^\prime(x)$ - obliczone recznie')
    green_patch = mpatches.Patch(color='green', label=r"$\int_{-3}^{1}f(x)$ - obliczone numerycznie")

    plt.legend(handles=[red_patch, blue_patch, cyan_patch, green_patch], loc='lower right')

    x = np.linspace(-4, 2, 10)
    x_dense = np.linspace(-4, 2)

    y_f = func(x)
    plt.plot(x, y_f, 'red', linewidth=2)

    y_deriv = derivative(func, x)
    plt.plot(x, y_deriv, 'blue', linewidth=2)

    y_own_deriv = own_deriv_func(x_dense)
    plt.plot(x_dense, y_own_deriv, 'cyan', linewidth=1)

    summo1 = definite_integral(func, a=-3, b=1)
    summo2 = own_integral_func(a=-3, b=1)
    print 'Całka oznaczona, numerycznie: %f' % summo1
    print 'Całka oznaczona, ręcznie: %f' % summo2

    current_figure = plt.gcf()
    current_figure.savefig('rachunek_rozniczkowy.png')

    plt.show()


def func(x):
    return -2 * (x ** 3) - 4 * (x ** 2) + (8 * x) + 1


def own_deriv_func(x):
    return -6 * (x ** 2) - 8 * x + 8


def own_integral_func(a, b):
    F = lambda x: -(1/2.0) * (x ** 4) - (4/3.0) * (x ** 3) + 4 * (x ** 2) + x
    return F(b) - F(a)


def derivative(fun, x):
    h = 0.2 # dx
    return (fun(x + h) - fun(x)) / h


def definite_integral(fun, a, b):
    axes = plt.gca()
    dx = (b - a) / 20.0

    summo = 0
    x = a
    while x < b:
        axes.add_patch(mpatches.Rectangle(xy=(x, 0), width=dx, height=fun(x), facecolor='green'))
        summo += dx * fun(x)
        x += dx

    return summo


if __name__ == '__main__':
    main()
Wynik:
Całka oznaczona, numerycznie: -26.080000
Całka oznaczona, ręcznie: -25.333333

19 czerwca 2016

MathJax - Hello World

Test MathJax do zapisywania formuł matematycznych.
Niech \(f\) będzie funkcją ciągła zdefiniowaną dla \( a \leq x \leq b \). Przedział \( [a, b] \) będzie podzielony \( n \) podprzedziałów o równej długości wynoszącej \( \Delta x = \frac{(b - a)}{n} \), tak że \(x_{0} = a \), a \( x_{n} = b \), będącymi końcami tych podprzedziałów i niech \( x_{1}^*, x_{2}^*,... , x_{n}^* \) będą dowolnymi punktami próbkującymi w tych przedziałach, \( x_{i}^* \in [x_{i-1}, x_{i}] \). Wówczas całkę oznaczoną z funkcji \( f \) w przedziale od \( a \) do \( b \) oznaczamy i definiujemy jako:
$$ \int_{a}^{b} f(x) dx = \lim_{n\to\infty} f(x)\sum_{i=1}^{n} f(x_{i}^*) \Delta x $$

3 maja 2016

{Machine Learning} Recipes

Google Developers na swoim kanale, rozpoczął serię filmów traktujących o nauczaniu maszynowym. Krótka i ciekawa forma, bardzo mi się podoba.



Odrobinę przerobiony przykład "Hello Wrold"
# http://scikit-learn.org/stable/
# https://www.continuum.io/
# sudo apt-get install python-scikits-learn

from sklearn import tree

# Collect training data
SMOOTH = 1
BUMPY = 0
APPLE = 0
ORANGE = 1

features = [[140, SMOOTH], [130, SMOOTH], [150, BUMPY], [170, BUMPY]]
labels = [APPLE, APPLE, ORANGE, ORANGE]

# Train classifier
clf = tree.DecisionTreeClassifier()
clf = clf.fit(features, labels)

# Make predictions
result = clf.predict([[160, 0]])

if result[0] == APPLE:
    print 'APPLE'
elif result[0] == ORANGE:
    print 'ORANGE'
else:
    'Result unknown'
Wynik:
ORANGE

28 marca 2016

vpython, gify i mechanika klasyczna

Od dawna planuje zabrać się za naukę mechaniki klasycznej. To kolejne podejście, tym razem jednak, zacząłem od poszukiwania narzędzi, które pomogą mi w nauce. Zaczęło się od bardzo fajnego artykułu na temat biblioteki vpython, linki poniżej i inne przydatne:
Za cel eksperymentu postawiłem sobie, wygenerowanie gif-a, z animacją ruchu. Liczyłem, że wystarczy do tego ImageMagic, jednak tworzenie gif-ów jest na tyle zagmatwane, że trzeba było skorzystać również z pakietu FFmpeg. Efekt nie jest do końca satysfakcjonujący. Od pewnego czasu, za bardzo skupiam się nad idealną wersją prototypu. Co więcej staram się znaleźć odpowiedzi na wszystkie pytania jakie się pojawią podczas jego wytwarzania, szczególnie te poboczne. Nie taka był idea tego bloga, czas więc na refleksję.

W każdym razie, oto przerobiony przykład "bouncing ball" z niewielkimi modyfikacjami. Po pierwsze, skorzystałem z biblioteki PIL (Python Image Library), aby tworzyć zrzuty ekranu kolejnych klatek animacji. Biblioteka działa jedynie pod systemem Windows, a jej zamiennik pyscreenshot nie zdał rezultatu. Jakoś się z tym pogodziłem. Druga sprawa, to warunek przerwania animacji, czyli moment gdy piłka znów znajdzie się w tej samej pozycji.
from visual import *
import ImageGrab    # from PIL


starting_height = 4
floor = box (pos=(0, 0, 0), length=4, height=0.5, width=4, color=color.blue)
ball = sphere (pos=(0, starting_height, 0), radius=1, color=color.red)
ball.velocity = vector(0, -1, 0)
dt = 0.01

frame = 0
while 1:
    rate (100)
    ball.pos = ball.pos + ball.velocity*dt
    if ball.y < ball.radius:
        ball.velocity.y = abs(ball.velocity.y)
    else:
        ball.velocity.y = ball.velocity.y - 9.8*dt

    file_name = 'img-' + '{fr:03d}'.format(fr=frame)  + '.png'
    frame += 1

    im = ImageGrab.grab((0, 0, 500, 500))  # screen box from (0,0)-(500,500)
    im.save(file_name)                     # save image to disk

    if ball.pos.y > starting_height:
        exit()
Skrypt wygenerował około 140 zrzutów ekranu, które trzeba było poddać obróbce, nieoceniony okazał się tutaj ImageMagic. Kluczowym problem jest wysterowanie czasu pomiędzy kolejnymi klatkami.
Wszystkie obrazki zawierały ramki Windows-owego okienka, które trzeba było usunąć:
Przycinanie zdjęcia za pomocą mogrify (z ImageMagic). Pozycje i rozmiar dobrałem eksperymentalnie.
mogrify -crop 413x411+9+30 +repage $(ls -v *.png)
Chociaż ImageMagic potrafi generować gif-y, jednak za żadne skarby nie mogłem skonfigurować właściwego opóźnienia, pomiędzy kolejnymi klatkami. Szperając po internecie udało się ten problem ominąć, wymaga to jednak kroków pośrednich, w postaci utworzenia filmiku z animacją, a następnie przepuszczenia go jeszcze raz przez ffmpeg i convert (ImageMagic). Magiczny zestaw komend:
# Filmik ze zdjęć
ffmpeg -r 100 -f image2 -i img-%3d.png video.avi

# Wyciąganie klatek z filmiku i zlepianie w gif-a
ffmpeg -i video.avi -vf scale=320:-1 -r 10 -f image2pipe -vcodec ppm - | convert -delay 10 -loop 0 - gif:- | convert -layers Optimize - output.gif

# Alternatywna wersja, też działa
ffmpeg -i video.avi -vf scale=320:-1 -r 10 -f image2pipe -vcodec ppm - | convert -delay 10 -loop 0 - output2.gif
W animacji jest jakiś uszczerbek jakości, tak jakby brakowało wszystkich potrzebnych klatek. Być może uda mi się kiedyś rozwiązać tą zagadką i odpowiednio dobrać parametry, wtedy też o nich napiszę. Próbowałem także innych rozwiązań, bezskutecznie próbując wysterować opóźnienie pomiędzy kolejnymi klatkami.
# Gif generowany tylko przez convert (ImageMagic)
convert -dispose none -delay 1.5 $(ls -v *.png) -coalesce output3.gif

# Gif generowany tylko przez ffmpeg
ffmpeg -f image2 -framerate 100 -i img-%3d.png output4.gif

16 marca 2016

Klient OpenVPN - pierwsze kroki

Postawienie dobrze zabezpieczonego połączenia VPN, jest jak się okazuje czynnością dość pracochłonną. Szczególnie warty uwagi jest pierwszy link, który opowiada o dobrym zabezpieczeniu całej usługi:
Moje pierwsze kroki, sprowadziły się do rozwiązania kilku problemów, związanych z systemem operacyjnym (Ubuntu) jak i usługodawcą VPN. Pierwsza próba odpalenia zakończyła się błędem:
Wed Mar 16 10:10:10 2016 ERROR: Cannot ioctl TUNSETIFF tap: Operation not permitted (errno=1)
Wed Mar 16 10:10:10 2016 Exiting due to fatal error
A więc klient, musi w jakiś sposób uzyskać prawa super użytkownika, aby działać na urządzeniu tun/tab, na co jest kilka rozwiązań:
Najprościej jest oczywiście, gdy posiadamy prawa root-a. Możemy wtedy wykonać komendę (gdzie w pliku secret.txt, w kolejnych linijkach zapisany jest login i hasło):
openvpn --config vpn_provider/conf.ovpn --ca vpn_provider/ca.crt \
        --auth-nocache --auth-user-pass secret.txt
Kolejny problem, z którym się spotkałem to niedziałające DNS-y. Czasami usługodawca VPN nie oferuje takiej usługi ze swojej strony, a ISP nie zgadza się na łączenie ze swoimi serwerami DNS, dla osób spoza sieci. DNS-owe zapytania, można przerzucić na router (192.168.1.1), co może nie być najlepszym pomysłem ze względów bezpieczeństwa, można też skorzystać z publicznych serwerów DNS (np. google). Nie wiem jak dokładnie wybierane są serwery DNS-owe z pliku /etc/resolve.conf, przez aplikacje, ale to co zaobserwowałem (przynajmniej w stosunku do komendy ping), warto wpisy o nowych serwerach podać jako pierwsze.
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 8.8.8.8
namseerver 8.8.4.4

28 lutego 2016

Android USB tethering

Android tethering i magiczny zestaw komend. Ale najpierw linki:
Należy rozpocząć od zainstalowania klienta DHCP jeżeli go nie ma, np.:
$ sudo apt-get install isc-dhcp-client
# Albo
$ sudo apt-get install dhcpcd5
Po podłączeniu telefonu do komputera i włączenie opcji tetheringu (Udostępnianie internetu | Router USB).
# Należy odnaleźć interfejs sieciowy podłączonego telefonu, będzie to np. enx01234
$ ifconfig -a

$ sudo dhclient enx01234
# Albo
$ sudo dhcpcd enx01234

# Test
$ route
$ wget -c example.com
Problem, który napotkałem to nie działające DNS-y, trzeba więc było dodać do /etc/resolv.conf publiczne DNS-y google:
$ cat /etc/resolv.conf

# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 127.0.1.1
nameserver 8.8.8.8
nameserver 8.8.4.4
Wszystko co pozostało to zautomatyzowanie całego procesu. Prawie ...

W przypadku mojego domyślnego ISP, pojawił się problem "powrotu". Najwyraźniej stara sesja DHCP, została utracona, a serwer nie chciał utworzyć nowej. Pomogły dwie komendy, które usunęły i zażądały nowej sesji.
$ sudo dhclient -r -v eth0
$ sudo dhclient -v eth0

27 lutego 2016

Reinstalacja VirtualBox-a wraz z extension pack-iem

Reinstalacja VirtualBox wraz z extension pack-iem. Najpierw należy ściągnąć pakiet (.deb) oraz extension pack (.vbox-extpack) w odpowiedniej wersji:
VirtualBox zaprotestuje, jeżeli mamy zainstalowaną starszą wersję, trzeba ja odinstalować:
$ sudo apt-get remove virtualbox-4.3
Proces instalacji:
$ sudo dpkg -i virtualbox-5.0_5.0.14-105127-Ubuntu-wily_amd64.deb

$ sudo VBoxManage list extpacks
Extension Packs: 1

$ sudo VBoxManage extpack uninstall "Oracle VM VirtualBox Extension Pack"
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Successfully uninstalled "Oracle VM VirtualBox Extension Pack".

$ sudo VBoxManage extpack install Oracle_VM_VirtualBox_Extension_Pack-5.0.14-105127.vbox-extpack 
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Successfully installed "Oracle VM VirtualBox Extension Pack".

$ sudo VBoxManage list extpacks
Extension Packs: 1
Pack no. 0:   Oracle VM VirtualBox Extension Pack
Version:      5.0.14
Revision:     105127
Edition:      
Description:  USB 2.0 and USB 3.0 Host Controller, Host Webcam, VirtualBox RDP, PXE ROM, Disk Encryption.
VRDE Module:  VBoxVRDP
Usable:       true 
Why unusable: 

13 stycznia 2016

[CppCon 2015] C++11/14/17 atomics and memory model: Before the story consumes you

Model pamięci jest największą zmianą jaką przyniósł nowy standard. A mechanizm atomic-ów na razie sprawiają mi najwięcej problemów. Być może znajdę kiedyś motywację, by bliżej się im przyjrzeć. W tej chwili wszystko co zrobiłem w tym kierunku to sucha lektura. Poniżej, bardzo fajny wykład z tegorocznego CppCon 2015 autorstwa Michaela Wonga, który rozjaśnił mi wiele kwestii.


2 stycznia 2016

[python] collections

Trzy klasy z pakietu collections, których nigdy wcześniej nie korzystałem, a okazały się niezwykle przydatne.
Bywa że do krotki chcemy wstawić na tyle dużo danych, że zaczynamy się gubić w tym, na której pozycji znajduje się to co nas interesuje. Zamiast tworzyć klasę z polami, można skorzystać z namedtuple.
from collections import namedtuple

User = namedtuple('User', ['name', 'address', 'email'])

user = User('Bob', 'blog.example.com', 'bob@example.com')
print('Name:  ' + user.name)
print('Web:   ' + user.address)
print('Email: ' + user.email)
Wynik:
Name:  Bob
Web:   blog.example.com
Email: bob@example.com
Counter pozwala na zliczanie elementów - zamiast dedykowanej pętli for.
from collections import Counter

indexer = Counter(['Bob', 'Alice', 'Bob', 'Bob'])
print(indexer['Bob'])
Wynik:
3
defaultdict jest klasą pozwalają na ustawienie domyślnej wartości, dla nowych elementów. Przydatne, gdy dodajemy coś do wartości i nie chcemy robić testu na to, czy taki element już istnieje.
from collections import defaultdict

d = defaultdict(lambda: '-')
d['Bob'] += 'one_'
d['Alice'] += 'two_'
d['Bob'] += 'three_'

print(d)
Wynik:
defaultdict(<function <lambda> at 0x7fbf33b27578>, {'Bob': '-one_three_', 'Alice': '-two_'})