ParenQuery

;;; parenquery -- simple chaining JS method calls for JQuery

;;; instead of manual:
;; PARENQUERY> (ps (chain foo bar baz))
;; "foo.bar.baz;"
;; PARENQUERY> (ps (chain foo bar (baz)))
;; "foo.bar.baz();"
;; PARENQUERY> (ps (chain foo (bar 1 2 3) (baz)))
;; "foo.bar(1, 2, 3).baz();"
;; PARENQUERY> (ps (chain (me.next)
;;                        (show "slow" (lambda ()
;;                                       (chain ($ this) (filter "li") (css "display" "list-item"))
;;                                       (chain ($ this) (children) (eq 0) (focus))
;;                                       (chain ($ elt) (fade-out))
;;                                       (chain ($ this) (children) (filter ".__more") (fade-in))))))
;; "me.next().show('slow', function () {
;;     $(this).filter('li').css('display', 'list-item');
;;     $(this).children().eq(0).focus();
;;     $(elt).fadeOut();
;;     $(this).children().filter('.__more').fadeIn();
;; });"

(defpackage #:parenquery
  (:use #:common-lisp #:parenscript)
  (:export #:chain))
(in-package #:parenquery)

(defun %chain-1 (first second)
  (if (listp second)
      `((slot-value ,first ',(first second)) ,@(rest second))
      `(slot-value ,first ',second)))

(defun %chain (first second &rest rest)
  (if rest
      (apply #'%chain (%chain-1 first second) rest)
      (%chain-1 first second)))

(defpsmacro chain (first second &rest rest)
  "Chain methods, as for JQuery (jquery.org)"
  (apply #'%chain first second rest))

;; This program is free software. It comes without any warranty, to
;; the extent permitted by applicable law. You can redistribute it
;; and/or modify it under the terms of the Do What The Fuck You Want
;; To Public License, Version 2, as published by Sam Hocevar. See
;; http://sam.zoy.org/wtfpl/COPYING for details.

GSoC status update, week 0.5

Common-lisp.net's Trac site is down for last few days or so, which made the work a bit harder. Nevertheless, first real code has been written. Identifier normalization seems to work. I introduced another dependency, Puri – a portable version of Allegro's net.uri. Identifiers will be internally represented by Puri URI objects; for XRI, if I get to it (support for XRI is optional), I will probably subclass URI, so that minimal API changes will be needed.

I am pondering now how to do HTML parsing for HTML-based discovery. One way would be to use CL-HTML-Parse, or pxmlutils – a port of Allegro's xmlutils. Both would require adding dependencies to the library, dragging along (in case of pxmlutils) ACL-compat Allegro portability layer. Other way would be to add HTML parsing to XMLS. This may, however, seem tricky to do right, because HTML is not as structured as XML, and there may be many corner cases (possibly unquoted tag attributes, optional close tags, and so on). I don't know at the moment, how other parsers handle misformed HTML, and HTML's corner cases. If there is no reliable parser, an interface to a tool like HTML Tidy will be needed – either FFI, or by running external program

Work done this half-week

Problems

Minor only: reviewing available servers and installing one took more time than I expected, because much of information I needed to choose (like supported OpenID version, or required libraries) was well hidden inside the software. I also spent a few hours on what turned to be a documentation error in SimpleID during its installation.

Plans for next half-week

  • Research and choose HTML parsing strategy
  • Implement HTML-based discovery
  • Write tests for discovery and HTML parsing

GSoC status update, week 0

Your hacking starts... NOW! Official coding period has started yesterday. Dependencies have been downloaded, first lines of code have been written, first commit has just been pushed to the repository. The real work has started; now it's time to write actual code. ;) From now on, updates will be posted twice a week, every Tuesday and Friday.

Work done this week

  • Initialized code repository
  • Did research and initial choices on libraries:
    • Hunchentoot and Drakma for initial HTTP server and client
    • Ironclad for cryptography-related stuff
    • FiveAM for unit tests
    • For XML, no final decision yet… I'll start with XMLS for its simplicity, and maybe move on if it doesn't work well
    • Probably will need something for safe random number generation, will leave that one for later and stick with (RANDOM), seeded with /dev/random if possible, for now
    • Possibly some library for parsing will be needed; CL-PPCRE, or maybe some variant of Meta?
  • Linked and described repository, needed libraries, darcsweb and cut-and-paste HOWTO for getting the code with dependencies on Wiki front page
  • Prepared workplace, without local OpenID Provider for testing yet

Problems

Small delays related with final exams. Didn't complete list of existing implementations and reference providers, neither read much about the XRI thing. Still have some exams this week, and at least two more on June 9 and 11, but they should not cause significant delays

Plans for next half-week

  • Finish list of implementation and providers
  • Set up local OpenID Provider on my workstation for testing
  • Initial work on ID normalization plus unit tests

Lemonodor-fame is but a hack away!

GSoC status update, week -1

This week I spent mostly fighting with infrastructure (Trac, web page, mailing lists, and so on), and reading further into specs. Just a week of research, and coding start date, May 26th, should be just right to actually start coding.

Today, I received a surprise book from Google. All the rumours on students' mailing list about it being beautiful are fully confirmed ;]

Work done this week

  • Further work on infrastructure: Trac versions, milestones, ticket types etc
  • Establishing rough roadmap, published at Roadmap page of project's Trac.
  • Completed referenes on ProtocolInformation Wiki page
  • Started a list of existing implementations and providers on ExistingImplementations Wiki page
  • More documentation reading: finished OpenID and Yadis; XRI and relevant RFCs are still left to read

Plans for next week

  • Initialize Darcs repository with code skeleton (directory structure, .asd file, package, etc), link darcsweb from main page and wiki
  • Finish list of existing implementation and providers
  • Complete list of libraries that I will use (especially cryptography and XML-related ones)

GSoC status update, week -2

Dla polskich czytelników: od teraz do września na blogu publikował będę raz lub dwa razy w tygodniu status swojego projektu w Summer of Code 2008 (piszę lispową implementację OpenID, strona projektu jest pod adresem http://common-lisp.net/project/cl-openid/). Jest to jeden z oficjalnych kanałów komunikacji związanej z projektem, więc wiadomości pojawiać się będą w języku angielskim.

This year, I got accepted to Google Summer of Code programme. I will work on Common Lisp implementation of OpenID protocol; project page is at http://common-lisp.net/project/cl-openid/, and full proposal is available on project's Trac Wiki at OriginalProposal page. I will publish status updates twice a week (weekly before coding, which starts May 26) on this blog, in category CL-OpenID (RSS). This is the first update, two weeks before coding start.

Work done this far

  • Discussed project organization with mentor, Anton Vodonosov;
  • Chosen the license (LLGPL), version control method (darcs), and hosting (common-lisp.net);
  • Created common-lisp.net project, with mailing lists and Trac Wiki and issue tracker;
  • Initial overall design, described on InitialDesign Wiki page;
  • Initial reading of the specification.

Plans for next week

  • Further reading into specifications, especially RFCs referred to by OpenID spec;
  • Estimating rough project time line;
  • Research on existing OpenID implementations for comparison, ideas and testing.

Statuetka idioty roku wędruje do...

Ku pamięci na przyszłość:

[japhy@trinitrotoluen japhy]$ cd leeloo.moo.pl/
[japhy@trinitrotoluen leeloo.moo.pl]$ ls 
~japhy  ~zombiwock
[japhy@trinitrotoluen leeloo.moo.pl]$ rm -rf ~japhy/
rm: cannot remove directory `/home/users/japhy/': Permission denied
[japhy@trinitrotoluen leeloo.moo.pl]$ rm -rf \~japhy/
[japhy@trinitrotoluen leeloo.moo.pl]$ 

Note to self: statyczny backup RESTowego serwisu WWW

Właśnie (jakoś od czternastej rano) przygotowuję raport na projekt zespołowy dla mojej kochanej uczelni. Od paru dni zastanawiałem się, jak do tego raportu dołączyć statyczną kopię Trac, którego używaliśmy do organizacji pracy. I nie żeby taka kopia to była moja nadgorliwość, prowadzący przedmiot sobie tego zażyczył.

Problem z tym jest podwójny. Po pierwsze, trac ma miłe RESTowe adresy nie kończące się na .html. Z tego powodu mirror strony ściągnięty bezpośrednio na dysk (wget -m adres) będzie później trudno otworzyć lokalnie. Z pomocą przychodzą dwie opcje wgeta:

-E
dodaje końcówkę .html do ściągniętych plików typu text/html, które tej końcówki nie mają w adresie
-k
Zamienia linki w ściągniętych plikach HTML tak, żeby lokalna kopia działała

Ale to tylko połowa problemów. Druga polega na tym, że oprócz ładnych RESTowych adresów strona rozgałęzia się w tysiące różnych zapytań GET, które zawierają różne warianty widoku. Jak zapuściłem ściąganie z tymi dwoma parametrami, po trzech godzinach działania i ponad 250 przeciągniętych megabajtach prawie samego tekstu dałem sobie spokój. Tylko jak powiedzieć wgetowi, żeby nie ściągał wszystkiego, co ma jakikolwiek znak zapytania?

Samemu wgetowi się nie da. Po prostu nie da. Tak czy inaczej będzie ściągał cały HTML, może go później skasuje (nie miałem na tyle cierpliwości, żeby sprawdzić). Odpada. Może z drugiej strony... ale nie tylko nie da się wgetowi podać lokalnego pliku robots.txt, ale też i w samym robots.txt nie da się zabronić dostępu do samych ścieżek z łańcuchem zapytania.

Nie byłoby jednak sensu pisać o tym publicznie, gdybym nie miał jakiejś formy rozwiązania. Do tego jest to rozwiązanie na tyle od dupy strony, że stwierdziłem, że warto je umieścić tutaj. Otóż, na serwerze, na którym działa ów trac, działa też mod_rewrite. Dopisałem szybko do .htaccess:

RewriteCond %{HTTP_USER_AGENT} ^Wget/ # Tylko dla naszego ściągania kopii, przeglądarki niech mają dostęp do wszystkiego
RewriteCond %{QUERY_STRING} !="" # Dla niepustego łańcucha zapytania
RewriteRule .* /drzewo [G] # Kierujemy na drzewo (G oznacza kod 410 Gone)

Wydaje się działać, co ku pamięci niniejszem odnotowuję.

Idealna licencja OSS

WTFPL. Open Source/Free Software w czystej postaci.

           DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
                   Version 2, December 2004 

Copyright© 2004 Sam Hocevar 
 14 rue de Plaisance, 75014 Paris, France 
Everyone is permitted to copy and distribute verbatim or modified 
copies of this license document, and changing it is allowed as long 
as the name is changed. 

           DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
  TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

 0. You just DO WHAT THE FUCK YOU WANT TO.

Aż mnie kusi, żeby napisać jakąś biblioteczkę, tylko po to, żeby była na powyższej licencji…

Nix – czysto funkcyjny menedżer pakietów

Wieki temu został mi podrzucony adres takiego cudaka jak Nix. Kliknąłem, przejrzałem, rzecz ogólnie olałem. Ładne, ale średnio przydatne. Ostatnio wróciłem… i muszę przyznać, że tym razem trafiło do mnie bardziej. Może dlatego, że w międzyczasie nauczyłem się paru bardziej teoretycznych rzeczy na temat komputerów i systemów, a może dlatego, że na roku poszła plotka, jakobyśmy powinni wybrać sobie temat magisterki, więc na mijane w sieci ciekawostki patrzę ostatnio pod nieco innym kątem.

Ale o co właściwie chodzi? Trudno rzecz zwięźle opisać, nie czyniąc przy tym nadmiernych uproszczeń. Autorzy projektu stwierdzili, że przestrzeń dyskowa jest rodzajem pamięci (co samo w sobie jest mało odkrywcze), więc do zarządzania nią można użyć mechanizmów od lat już używanych do zarządzania pamięcią operacyjną – co jest już ciekawsze. Istnieją języki programowania, które nie wspierają nadpisywalnych danych; zamiast nadpisywalnych zmiennych są niemutowalne wartości przypisywane etykietom. Takie języki nazywamy funkcyjnymi. Nix jest czysto funkcyjnym systemem pakietów.

Przestrzeń składowa

Pakiety są opisywane funkcjami nieposiadającymi efektów ubocznych, zapisywane w unikalnych katalogach przestrzeni składowej (store) i opisywane oprócz nazwy i numeru wersji haszem całej znanej konfiguracji. W jednym systemie może być więc zapisanych jednocześnie wiele wersji i wariantów tego samego pakietu. Każdy pakiet zależy od konkretnej wersji i wariantu pakietów, dla których został przebudowany (i te pakiety też są częścią konfiguracji – równie dobrze jak mieć Firefoksa 1.x, 2.x i 3.x na jednym systemie, nie mamy problemów ze skompilowaniem tego samego programu w tej samej wersji, ale z różnymi wersjami jakiejś biblioteki). Ponieważ w ścieżce występuje hasz jednoznacznie określający wariant pakietu, mamy łatwy dostęp do całego grafu zależności przy użyciu zwykłego polecenia grep.

Co więcej, pełny opis zależności jest tutaj wymuszony przez system. W tradycyjnych systemach zarządzania pakietami (rpm, dpkg, slackowe tarballe…) jeśli nie podałem w opisie pakietu któregoś z pakietów wymaganych do jej kompilacji, to jeśli posiadam ten pakiet w systemie, paczka skompiluje się i tak. U mnie. U kogo innego – niekoniecznie się skompiluje, tym bardziej niekoniecznie skompiluje się tak samo jak u mnie; zależy to od pakietów obecnych na kompilujących systemie. W Nix taki myk jest po prostu niemożliwy. Paczka, która nie jest określona w opisie budowanego pakietu, jest dla niego po prostu niewidoczna.

Domknięcia i widoki

Dobra, no to opisaliśmy w skrócie własności składowania pakietów w Nix. Podejrzewam, że u tych z Was, którzy dotarli do tego miejsca z wyłączoną już lampką Ale o co w tym chodzi?, zapaliła się w jej miejsce lampka Ale jak się w tym połapać??. Dobre pytanie. I tutaj przychodzą na myśl dwa kolejne pojęcia pochodzące z języków funkcyjnych i zarządzania pamięcią operacyjną: domknięcia i widoki.

Nie chcę teraz omawiać pierwotnego znaczenia tych pojęć; zainteresowani mogą zerknąć choćby w Wikipedię. Skupię się za to na opisaniu znaczenia tych pojęć w Nix. Do rzeczy: domknięcie pakietu to jest pakiet plus wszystkie pakiety, od których zależy, plus wszystkie pakiety, od których one zależą, itd. – słowem, komplet pakietów koniecznych do używania danego pakietu. Skoro znamy pełne zależności każdego z pakietów, nietrudno jest dla każdego używanego pakietu wyznaczyć domknięcie.

Widok jest to zestaw pakietów widocznych na raz. Używane są do kompilacji (aby kompilowany pakiet widział wszystkie potrzebne do kompilacji narzędzia i biblioteki), a także – co chyba istotniejsze – do implementacji środowisk użytkownika. Użytkownik widzi w swoim środowisku tylko wybrane przez siebie pakiety w wybranych wersjach – i może zmieniać środowiska wedle potrzeb czy zachcianek.

Przebieg instalacji i deinstalacji pakietu

W ramach optymalizacji implementacji, wszystko, co się da, jest robione na symlinkach (lub, na systemach nie obsługujących symlinków, skryptach odnoszących się do innych katalogów). W efekcie, używane jest minimum miejsca, a instalacja przebiega następująco:

  • System upewnia się, że w przestrzeni składowej znajduje się całe domknięcie pakietu. Instalowany pakiet i brakujące zależności są dodawane do składu.
  • Raz zapisany do składu komponent pozostaje niezmienny i tylko do odczytu. Zatem, na podstawie bieżącego środowiska użytkownika, tworzone jest w składzie nowe środowisko, zawierające dotychczas widoczne komponenty i zainstalowany właśnie komponent.
  • Symlink „bieżące środowisko” jest przenoszony na właśnie utworzone środowisko zawierające nowy program.

Podobnie przebiega aktualizacja i usuwanie pakietu. W efekcie użytkownik zawsze widzi spójny system i nie jest narażony na nieprzyjemności podczas instalacji czy uaktualnienia. Do tego, jeśli zmiana pójdzie nie tak, zawsze może jakby nigdy nic wrócić do wcześniejszego środowiska.

Do tego, każdy użytkownik może mieć osobne środowisko. Administratorzy zapewne od razu widzą zastosowanie tego systemu: użytkownik nie musi być człowiekiem, może to być serwer o ściśle określonych wymaganiach w kwestii bibliotek i programów. Każdy webapp uruchomiony na maszynie może mieć swoje ulubione środowisko (i nic ponad to), nie tworząc konfliktów z resztą systemu! Więcej, możemy w jednym systemie mieć bez bólu głowy środowisko rozwojowe i produkcyjne czy też staging.

Śmieciarka

Pytanie, co z nieużywanymi już komponentami po deinstalacji czy uaktualnieniu pakietu? Albo z komponentami potrzebnymi do zainstalowania pakietu, ale po instalacji już zbędnymi? Przy takim podejściu, składowisko w mgnieniu oka napuchnie ponad wyraz!

Na pomoc przychodzi kolejne (spokojnie, to już ostatnie) pojęcie z zakresu zarządzania pamięcią: odśmiecanie. W każdej chwili możemy składowisko odśmiecić, czyli usunąć niewidoczne z żadnego środowiska użytkownika (i, jeśli chcemy, paru wersji tego środowiska wstecz) komponenty. Przy takim mechanizmie to jest proste: śmieciarka bierze wszystkie środowiska, które chcemy zachować, oznacza komponenty w domknięciach każdego komponentu tych środowisk jako potrzebne, po czym usuwa całą resztę.

NixOS i Nix na PLD

Na zakończenie, dla sceptyków twierdzących, że w praktyce żadne nietrywialne oprogramowanie nie zniesie takiej dyscypliny: NixOS – dystrybucja Linuksa oparta w pełni o Nix. Używa Niksa nie tylko do zarządzania pakietami oprogramowania, ale też do zarządzania konfiguracją. Poza katalogiem /nix, system praktycznie nie istnieje. Nie ma /bin (poza linkiem /bin/sh do odpowiedniego komponentu Nix), /lib, /usr… można zobaczyć to na screenshocie ze strony projektu.

Sam sprawdziłem, system instaluje się i wstaje. Wiele więcej na razie nie zdziałałem, obecnie bawię się Niksem raczej na własnej workstacji na PLD. Komputer i instalacja PLD jest 64-bitowa, a Niksa zaczynam używać do zarządzania potrzebnym mi 32-bitowym oprogramowaniem (głównie Opera i inne binarki). Poldek niby obsługuje multiliba, ale słabawo – tą metodą mam dodatkową zabawkę ;)

Nix na PLD

Bardziej jako notka do siebie, bo wątpię, czy ktoś z Czytelników wytrwał do tego miejsca. Żeby korzystać sobie z Niksa w PLD, trzeba:

  • Skompilować i zainstalować paczkęnix: ./builder nix (jeśli nie wiesz, o co chodzi: http://developer-doc.pld-linux.org/baseciq/slack2pld.html)
  • W moim przypadku (inna architektura Nix niż systemu), polecenia nix-env należy poprzedzać setarch i686, a w /etc/nix/nix.conf ustawić odpowiednio zmienną system
  • Dodać i zaciągnąć kanały, poinstalować paczki… jak w manualu Niksa Wszystko działa zasadniczo OOTB. Powinno działać nawet uaktualnienie Niksa w Nix (wtedy można z macierzystego PLD usunąć spokojnie paczkę z Niksem), ale tego nie próbowałem.

Nie próbowałem też jeszcze stwarzać różnych środowisk, opisywać i budować własnych paczek, za to ten artykuł dodaję z:

japhy@lizard:~/rpm/SPECS % which opera            
~/.nix-profile/bin/opera
japhy@lizard:~/rpm/SPECS % ps awux |grep '[o]pera' 
japhy     1223 22.8 25.6 405148 378256 pts/15  S    21:40  23:07 /nix/store/bayygjghpz8mcbcwbccp0mgj8gcgv006-opera-9.24-20071015.5/lib/opera/9.50-20071024.5/opera
japhy     1233  0.0 25.6 405148 378256 pts/15  S    21:40   0:00 /nix/store/bayygjghpz8mcbcwbccp0mgj8gcgv006-opera-9.24-20071015.5/lib/opera/9.50-20071024.5/opera
japhy@lizard:~/rpm/SPECS % 

W miarę zabawy pewnie dotrę do ciekawszych zastosowań i ficzerów, których z pewnością nie omieszkam opisać. Na razie to byłoby wszytko – i tak wpis wyszedł potwornie długi… dobranoc.

Kategorie

Archiwum