Linksys WAG120N – zmiana adresu IP z poziomu skryptu

Korzystając z Internetu czasem warto zmienić adres IP pod jakim jesteśmy widziani w sieci. Umożliwi to przykładowo pobranie następnego pliku bez oczekiwania. Oczywiście nasz ISP musi udostępniać taką możliwość (tak jest, dla przykładu z Neostradą).

W ruterze Linksys WAG120N można to zrobić za pomocą panelu kontrolnego dostępnego poprzez protokół HTTP. Czyli trzeba:

  1. wejść w przeglądarce pod właściwy adres
  2. wpisać nazwę użytkownika i hasło (lub zaakceptować zapamiętane przez przeglądarkę)
  3. przejść do Status (co)
  4. kliknąć Disconnect
  5. poczekać chwilkę
  6. kliknąć Connect
  7. poczekać chwilkę

Jak widać jest to sporo pracy. Szczęśliwie można to zautomatyzować za pomocą skryptu. Wystarczy skorzystać z sniffera (ja użyłem Wireshark).

W wyniku tego powstał poniższy skrypt powłoki (testowany w Bashu i Zsh). Mam nadzieję, że się komuś przyda. Wystarczy dokleić poniższy kod do pliku konfiguracyjnego powłoki (odpowiednio .bashrc lub .zshrc). No i należy pamiętać, że działa dużo lepiej jeśli odpowiednio ustawi się zmienne USER i PASS.

my-ip() {
  wget 'http://checkip.dyndns.org/' --quiet -O- | sed -e \
    's/[^0-9]*\([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/g'
}

change-ip() {
  router-op() {
    USER="user"
    PASS="password"
    ADDR="http://192.168.1.1/setup.cgi"
    wget --http-user=$USER --http-password=$PASS $ADDR \
      --post-data $1 --quiet -O/dev/null 
  }
  REST='&this_file=Status.htm&next_file=Status.htm&message='
  echo Old IP: `my-ip`
  router-op 'ctype=pppoa&ifstatus=Up&todo=disconnect'$REST
  sleep 4
  router-op 'ctype=pppoa&ifstatus=Up&todo=connect'$REST
  sleep 8
  echo New IP: `my-ip`
}

Reddit albo zdrowie (psychiczne)

Po dłuższym czasie używania reddit.com postanowiłem zarejstrować się w tym serwisie. Po to by móc w łatwy sposób oglądać wiadomości z kilku grup (jak choćby programming, compsci, coding czy python). Niestety samo dodawanie z użytecznością (usability) nie ma za wiele wspólnego.

Zamiast zastosować klasyczne checkboxy czy ich proste odpowiedniki użyto czegoś takiego:

Intuicja podpowiada, że zielony kolor oraz znak plus oznacza „dodane” a czerwone z minusem oznacza „usunięte”. Sugestia na stronie nic nie pomaga (głosi ona: click the +frontpage or -frontpage buttons to choose which reddits appear on your front page.).

Okazuje się, że jest odwrotnie. Zamiast „dodane” zielone oznacza „dodaj” a czerwone nie „usunięte” ale „usuń”. Jest to bardzo mylące a w efekcie frustrujące.

Programowania funkcyjnego z Pythonem spotkania

Jacek Laskowski opublikował wczoraj na swoim blogu ciekawą notkę Programowania funkcyjnego z Clojure początki niełatwe (szczególnie mentalnie). Myśli o programowaniu funkcyjnym siedzą mi w głowie od ponad roku, więc przeczytałem ją z zainteresowaniem. Na końcu zamieścił małe wyzwanie: by przepisać podanego przez niego jednolinijkowca do Javy.

(doseq [linia (map (fn [[h s]] (str h " (" s ")")) (partition 2 [1 2 3 4 5 6 7 8 9 0]))] (println linia))

Java to nie jest mój ulubiony język, więc postanowiłem sprawdzić jak by dało się to zrobić w Pythonie (który posiada lekkie wsparcie tego paradygmatu funkcyjnego).

Do dzieła

Na początek mały problem – Python nie posiada wbudowanej funkcji partition. Trzeba ją samemu napisać. Na przykład tak:

def partition(size, seq):
    result = []
    for i in seq:
        result.append(i)
        if len(result) == size:
            yield tuple(result)
            result = []

Uwaga: to jest odpowiednik clojure.core/partition(n coll). Nie obsługuje ani step ani pad.

Potem już idzie z górki:

print "\n".join(map(lambda t: "%i (%i)" % t, partition(2, [1, 2, 3, 4, 5, 6, 7, 8, 9, 0])))

Można to napisać nawet bardziej w stylu Pythona (poprzez zastąpienie funkcji map i lambda przez listę składaną):

print "\n".join(["%i (%i)" % t for t in partition(2, [1, 2, 3, 4, 5, 6, 7, 8, 9, 0])])

Programowanie funkcyjne?

Kod, który w Clojure zajmował 106 znaków dało się skrócić do odpowiednio 92 i 87 znaków.

Co więcej udało się z niego usunąć efekty uboczne i sekwencyjność wprowadzoną przez doseq. Cały napis jest budowany w pamięci a dopiero następnie wyświetlany – co jest bardziej funkcyjne.

W Clojure dało by się to zrobić za pomocą kodu:

(println (apply str (interpose "\n" (map (fn [[h s]] (str h " (" s ")")) (partition 2 [1 2 3 4 5 6 7 8 9 0])))))

Przy okazji: to jest prawdopodobnie pierwsza linijka mojego kodu w tym języku więc mogła by być lepsza.