Ctrl+Alt+Dell

10. lis 2011

Strona firmy Dell jest spe­cjalna. Pod koniec paź­dzier­nika zło­ży­łem tam zamó­wie­nie, pró­buję zatem usta­lić jego aktu­alny stan. Zwłasz­cza, że pie­nią­dze zdą­żyli już wziąć. Po zalo­go­wa­niu na swoje konto otrzy­muję taki oto komunikat:

Witaj, Custo­mer (nie jesteś Custo­mer?)

Po przej­ściu do listy zamó­wień zaś:

Witaj,      (to nie Ty)

Oczy­wi­ście, że to nie ja, nie mam wszak na imię <odgłos upa­da­ją­cej kla­wia­tury>. Ale tuż niżej jest jesz­cze lepiej:

Przy­kro nam, ale wygląda na to, że w poda­nym okre­sie nie mie­li­śmy od Pań­stwa żadnych zamó­wień. Pro­simy wybrać inny okres i spró­bo­wać ponow­nie. Jeśli uwa­żasz, że ta wia­do­mość została dostar­czona do Cie­bie omyłkowo,

Jakim okre­sie? Jak wybrać inny okres? Jaka wia­do­mość? I co, jeśli została dostar­czona omył­kowo? Kli­kam jed­nak „Wyświetl inne zamó­wie­nie”, wpi­suję numer zamó­wie­nia i swój adres e-mail (ten sam, na który jestem zalo­go­wany). Poja­wia się zamówienie.

Stan: Wysłano

Sza­co­wana data dostawy: Zamó­wie­nie wysłane

Numer śledze­nia: JJD0000¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

Wysłano dnia: 2011-11-04

Po klik­nię­ciu odno­śnika do śledze­nia zamó­wie­nia, sytu­acja nieco się kla­ruje. Tra­fiam bowiem na stronę hisz­pań­skiego (!) DHL, który — o dziwo — mojej paczki nie ma:

Situación de un Envío

Este número de expe­di­ción no exi­ste en nuestro sistema, vuelva a intentarlo.

Si no conoce el número de expe­di­ción, puede inten­tarlo intro­du­ciendo el número de referencia

Si no conoce nin­guna de estas dos varia­bles, puede uti­li­zar la opción ‘selec­ción’ del menú ‘Servi­cio Cliente’.

Cie­kawe, czy odpi­szą mi na maila?

Update: Odpi­sali. Zamiast męczyć się ze stroną Della, prze­syłki można śledzić na dedy­ko­wa­nej stro­nie DHL. Trzeba tylko podać swój numer klienta Dell i numer zamó­wie­nia, który znaj­dziemy w tema­cie e-maila z potwier­dze­niem zamówienia.

Pięć setek szaleństwa

5. lis 2011

Wtem!

— Leży!

Pro­duk­cja? Ale tutaj?

Traceback (most recent call last):
  File "/var/www/foo/catalogue/views.py", line 252, in get
    product = Product.objects.get(upc=tokens[0])
  File "/usr/lib/python2.6/site-packages/django/db/models/manager.py", line 132, in get
    return self.get_query_set().get(*args, **kwargs)
  File "/usr/lib/python2.6/site-packages/django/db/models/query.py", line 351, in get
    % (self.model._meta.object_name, num, kwargs))
TypeError: 'DoesNotExist' object is not callable

Odśwież. Działa. Ki czort? Odśwież. Leży. Działa — działa — leży — działa. Wynik zdaje się zale­żeć od pro­cesu, który aku­rat obsłuży zapytanie.

No dobrze, zobaczmy, co…

        raise self.model.MultipleObjectsReturned("get() returned more than one %s -- it returned %s! Lookup parameters were %s"
                % (self.model._meta.object_name, num, kwargs))

Wyją­tek. W trak­cie rzu­ca­nia wyjątku. Wbu­do­wa­nego w klasę modelu.

Wdech, wydech. Drugi wor­ker dostał. Dzi­wacz­nie poskrę­cane frag­menty jego wnętrz­no­ści zasy­pują mi skrzynkę.

Wdech, wydech, grep.

Zanim się przedar­łem, stra­ci­li­śmy jesz­cze trzech. W sumie połowa zwi­jała się tam i char­czała wewnętrz­nymi błę­dami. Wytrzy­maj­cie, jesz­cze tylko kilka pli­ków. I jest.

        try:
            product = Product.objects.get(upc=product_upc)
        except Product.DoesNotExist, Product.MultipleObjectsReturned:
            # …

Zasadzka — sztuk trzy w pro­jek­cie — ładnie nas urzą­dzili. Jeden koniec kodu powoli kopie dołek pod dru­gim. Pułapki udało się usu­nąć, ale tam­tym już nikt nie pomoże. Przy­sła­nie na pro­duk­cję posił­ków zaj­mie mini­mum trzy dni. Pozo­staje tylko patrzeć, jak jeden po dru­gim toną w tym dzi­wacz­nym morzu bez­rad­no­ści, ser­wu­jąc skom­pli­ko­wane doku­menty, jed­nak dła­wiąc się na naj­prost­szych rze­czach. Zostali sami. Oni i pięć setek szaleństwa.

Kur­tyna. Nie­sto­sowne słowa cisną mi się na usta, ubli­żać chcę składni, albo­wiem łaknę Pythona trze­ciej inkarnacji.

Django: TemplateResponse

17. maj 2011

Przy­szło Django 1.3, poja­wiła się paskudna imple­men­ta­cja class-based views, direct_to_template zostało ozna­czone jako prze­sta­rzałe. Ale poja­wił się też godny następca, choć z class-based views nie ma nic wspólnego.

Nie piszemy więc tak:

from django.shortcuts import render_to_response
from django.template import RequestContext

def foo(request):
    # ...
    return render_to_response('foo.html', {'bar': baz},
            context_instance=RequestContext(request))

Nie piszemy też tak:

from django.views.generic.simple import direct_to_template

def foo(request):
    # ...
    return direct_to_template(request, 'foo.html', {'bar': baz})

Ani ­— tym bar­dziej — tak:

from django.views.generic import TemplateView

def foo(request):
    # ...
    return TemplateView.as_view(template_name='foo.html')(request, bar=baz)

Dro­dzy pań­stwo, zamiast powyż­szych używamy:

from django.template.response import TemplateResponse

def foo(request):
    # ...
    return TemplateResponse(request, 'foo.html', {'bar': baz})

Google Talk: authentication failure

6. maj 2011

Od wczo­raj­szego wcze­snego popo­łu­dnia nie mogłem się zalo­go­wać na swoje konto GTalk za pomocą żadnego komu­ni­ka­tora. Nic, zero, nada. GMail nadal dzia­łał bez zarzutu, czat na stro­nie logo­wał się momen­tal­nie, słońce świe­ciło, a Elvis wciąż był mar­twy. Zaczą­łem podej­rze­wać najgorsze.

Kiedy przy­je­cha­łem do domu, oka­zało się, że mia­łem rację — koń­czyło mi się piwo. Nie­zra­żony, spró­bo­wa­łem mimo wszystko sko­rzy­stać z komu­ni­ka­tora. Nie­stety — z podob­nym skut­kiem. Powoli zaczy­na­łem przy­pusz­czać, że coś jest nie tak. Sprawa była gru­bymi nićmi szyta. Bez wąt­pie­nia komuś zale­żało, by zerwać moje kon­takty z Karo­lem z warzyw­niaka pod oknem. Czyżby cena ogór­ków szklar­nio­wych miała wkrótce prze­kro­czyć cenę cukru, a ten biedny chło­pak pró­bo­wał mnie ostrzec?

Dziś rano wzno­wi­łem docho­dze­nie. Już w tram­waju byłem pewien, że ktoś mnie śledzi. Jakie jest bowiem praw­do­po­do­bień­stwo, by sześć­dzie­siąt trzy osoby jechały aku­rat w tym samym kie­runku, co ja? Dotar­łem do biura, by zaraz po wej­ściu wyto­czyć naj­cięż­sze działa: się­gną­łem do działu pomocy Google.

Jeśli zatem i cie­bie chcą pozba­wić kon­taktu z Karo­lem, rychło wnijdź pod adres wska­zany poniżej:

https://www.google.com/accounts/DisplayUnlockCaptcha

Reanimacja współczesnego systemu

20. mar 2011

Plotki na temat mojej śmierci były oczy­wi­ście grubo… aaru­uaaaarr­r­ghh­h­blargh. Nie­stety, rów­nie dobrze poczuł się mój lap­top po ostat­niej aktu­ali­za­cji pakietu upstartPLD.

Ku pamięci potom­nych przed­sta­wiam zatem prze­pis na dopro­wa­dze­nie do w miarę dzia­ła­ją­cego stanu sys­temu wypo­sa­żo­nego we „wszyst­kie te nie­po­trzebne wodotryski¹”.

¹ Tak nie­któ­rzy piesz­czo­tli­wie okre­ślają udev, a wła­ści­wie cokol­wiek powsta­łego po sta­tycz­nej struk­tu­rze /dev, może z wyjąt­kiem epoki lodowcowej.

Zaczy­namy tra­dy­cyj­nie, od pomi­nię­cia pro­cesu init (przy­kład dla grub2):

linux /boot/vmlinuz-2.6.37.4-1 root=/dev/sciezka/do-root init=/bin/sh

Następ­nie odzy­sku­jemy pod­sta­wowe funk­cje życiowe:

mount / -o remount,rw
mount /proc
mount /sys
export PATH=$PATH:/sbin:/usr/sbin
udevd &
udevadm trigger
dbus-daemon --system &
NetworkManager &

Uru­cho­miona w ten spo­sób kon­sola może odma­wiać prze­ry­wa­nia zadań przez Ctrl+C, ale zawsze można do tego celu użyć Alt+SysRq+I.

Django, except IntegrityError

15. gru 2010

Jeden mały, nie­winny szcze­nia­czek o maśla­nych oczkach zostaje gdzieś na świe­cie żywcem prze­mie­lony na karmę dla kotów za każ­dym razem, kiedy piszesz coś takiego:

try:
    # ...
except IntegrityError:
    return None

Łapa­nie IntegrityError jako metoda wykry­wa­nia pro­ble­mów jest rów­nie dobrym pomy­słem, co wymiana czuj­ni­ków dymu na urzą­dze­nie wykry­wa­jące odgłos syreny nad­jeż­dża­ją­cej straży pożarnej.

Błąd na pozio­mie bazy danych jest nie­od­wra­calny. Nie można nic napra­wić. To jak pójść pośmiert­nie do leka­rza. Połknię­cie wyjątku bez dal­szej pro­pa­ga­cji to tylko dodat­kowe punkty za styl. Dzięki temu wszyst­kie otwarte trans­ak­cje (z izo­lu­jącą włącz­nie) wła­śnie stały się bez­u­ży­teczne, a naj­bliż­sza ope­ra­cja na bazie danych spo­wo­duje spek­ta­ku­larny zgon całej aplikacji.

Wersja obrazowa

Twój kod pró­buje dywa­ni­kiem z kibla gasić ogień w domu, w któ­rym dawno złusz­czyły się tapety i znik­nęły meble. W domu, który sam pod­pa­lił. Nie­zbyt zado­wo­lony z rezul­ta­tów wycho­dzi więc przed budy­nek i dusi stra­ża­ków wężem. Po wszyst­kim, gwiż­dżąc, z rękoma w kie­sze­niach, odcho­dzi w stronę zacho­dzą­cego słońca, po dro­dze mija­jąc sąsiada — powoli spo­pie­la­ją­cego się we wła­snym ogródku.

Jeśli masz telefon w Plusie…

1. gru 2010

Zacznij od wysła­nia na (dar­mowy) numer 8010 SMS o tre­ści STOP. Położy to kres kre­tyń­skim rekla­mom z rodzaju:

MATKO BOSKA, KONIEC ŚWIATA, POTWIERDŹ SWÓJ NUMER i wygraj batonik.

Suk­ces zosta­nie potwier­dzony przez wiadomość:

Numer zostal wypi­sany z listy wysyl­ko­wej. Dziekujemy.

Teraz czas wypi­sać się z ofert i pro­mo­cji. W tym celu wyślij na (rów­nież dar­mowy) numer 8000 SMS o tre­ści SPRZECIW. Kiedy i ten przy­czó­łek wroga się podda, otrzy­masz list kapitulacyjny:

Twoj SPRZECIW na komu­ni­ka­cje mar­ke­tin­gowa kana­lami elek­tro­nicz­nymi zostal zare­je­stro­wany w systemie.

For great justice!

O DHL i najdroższych koszulkach na świecie

24. lis 2010

Gram. Cał­kiem sporo. Posta­no­wi­łem sobie spra­wić koszulki, któ­rymi pro­mo­wany był Por­tal 2. Jasną i ciemną. Na pol­skie warunki tanio nie jest, ale koszulki wyglą­dają naprawdę fajnie.

Zama­wiam więc. $39.98 plus dostawa. Za $20, bo z Ame­ryki. Do mojego zamó­wie­nia mogą zostać doli­czone dodat­kowe podatki, akcyzy i opłaty celne. Kon­ty­nuuj do płatności.

Płacę. A raczej pró­buję. Płat­ność kartą kre­dy­tową została odrzu­cona przez mojego ope­ra­tora. Ponów. Płat­ność kartą kre­dy­tową została odrzu­cona ponow­nie. Trudno, zapłacę przez Pay­Pal. Klik. Klik. Tak pozby­łem się 197,91 PLN. W teorii.

W prak­tyce pozby­łem się bowiem 591,91 PLN. Bank płat­no­ści odrzu­cił, ale pie­nią­dze uznał za wydane. Cóż, Valve mnie raczej nie okrad­nie. Minie czas blo­kady środ­ków i odda­dzą. Tak koń­czy się środa.

Jest pią­tek. Dzwoni telefon.

Anna z DHL przy­go­to­wuje się do odprawy cel­nej mojej paczki, która lada chwila trafi z lot­ni­ska w Lip­sku do Izby Cel­nej we Wro­cła­wiu. Musi wie­dzieć, z czego zro­bione są koszulki i jak zamie­rzam ich uży­wać. Podaję adres e-mail, dostaję listę doku­men­tów do przedłożenia.

Pod­pi­suję upo­waż­nie­nie dla DHL do repre­zen­ta­cji przed orga­nami cel­nymi. Gdy­bym wie­dział, co mnie czeka, zapre­zen­to­wał­bym także swój organ. Nie uprze­dzajmy jed­nak fak­tów. Pod­pi­suję świstek, że zobo­wią­zuję się koszu­lek nie sprze­dać w celu zarob­ko­wym. Została dekla­ra­cja zawar­to­ści, mate­ria­łów i inten­cji. Napi­sa­łem zgod­nie z prawdą:

Są to dwie koszulki z krót­kim ręka­wem. Mam nadzieję, że zro­bione są z bawełny. Będę w nich dziar­sko hasał po mie­ście, niczym rączy rumak po bez­kre­snych ste­pach w poran­nej rosie.

W ponie­dzia­łek o siód­mej pięć­dzie­siąt cztery rano (słow­nie: w nocy) dzwoni tele­fon. Odbiera Asia. Anna z DHL dzwoni spy­tać, z czego zro­bione są koszulki (sic!). Jest to tak praw­do­po­dobny sce­na­riusz, że — patrząc na swoją kobietę — sam sie­bie zaczy­nam podej­rze­wać o romans. O godzi­nie 11:35 odbie­ram kolejny tele­fon. Anna nie może wytrzy­mać bez mojego cudow­nego głosu, tym razem chce poznać także kształt rze­czo­nych koszu­lek. Nie pyta o roz­miar, co nie­stety niwe­czy próby wyobra­że­nia sobie mojej boskiej figury. Mają już wszystko potrzebne do odprawy.

I tak tra­fiamy na środę, czyli dziś. Rano wita mnie infor­ma­cja, iż odprawa celna została zakoń­czona, cła impor­to­wego nie nali­czono i na konto Izby Cel­nej winien jestem prze­lać należny poda­tek w kwo­cie 88 PLN. Kurwa, wróć! Osiem­dzie­siąt osiem? Przez zero koma dwa dwa daje… cztery stówy jak nic. Chwy­tam za telefon.

Dwie kolejne godziny spę­dzam dzwo­niąc do mojej nie­do­szłej kochanki. Jest gorzej, niż zwy­kle. Jesz­cze nie byli­śmy w łóżku, a już nie chce ze mną roz­ma­wiać. Po dwóch godzi­nach słu­cha­nia sygnału wol­nej linii, Ania (teraz to już pra­wie rodzina, nawet do rodzi­ców tak czę­sto nie dzwo­nię) odbiera tele­fon. Mówi, że wszystko się zga­dza, bo prze­cież stawka podatku jest 22%. Z tym, że ja stawki VAT znam. Pytam o podstawę.

Prze­cież 22% z 402 PLN to 88 PLN. Czuję się jak pilot myśliw­ski na manew­rach, krew w moim mózgu osiąga przy­spie­sze­nie rzędu 9G. Czte­ry­sta. Dwa. Złote. Ania spraw­dza, skąd. Oka­zuje się, że na fak­tu­rze dołą­czo­nej przez Ame­ry­ka­nów nie było ceny dostawy, więc DHL wpi­sał, co uważał.

Zaczy­nam się goto­wać. O kolor metki i ściegi na szwach to by mieli kogo spy­tać. Pew­nie o szó­stej w nocy dzwo­ni­liby z pyta­niem o tem­pe­ra­turę pra­nia. W obli­czu tra­ge­dii, jaką jest brak ceny dostawy na fak­tu­rze, sta­nęli bez­radni i w wyniku rzutu kostką wpi­sali 283 PLN. Nie mogli się dowie­dzieć. Nie, żeby na ten przy­kład byli w sta­nie usta­lić, na ile sami ska­so­wali Valve, prze­cież DHL nie udzieli takiej infor­ma­cji sam sobie („ale oni mówią do nas po angielsku!”).

To oczy­wi­ste, że inte­li­gentny czło­wiek zamó­wiłby koszulki o war­to­ści 119 PLN i kazał je dostar­czyć kurie­rowi za 283 PLN. A przy­naj­mniej każdy tak inte­li­gentny, jak agenci celni DHL.

Zło­ży­łem rekla­ma­cję, jed­nak jestem pra­wie pewien, że do czasu jej roz­pa­trze­nia minie ter­min uisz­cze­nia opłat cel­nych. Wobec tego będę musiał te pie­nią­dze zało­żyć. Będzie to moment, w któ­rym chwi­lowa cena dwóch kawał­ków bawełny osią­gnie 679,91 PLN. Zakła­da­jąc, że DHL do tego czasu nie nali­czy „dodat­ko­wych opłat według aktu­al­nie obo­wią­zu­ją­cego cen­nika”. Koszu­lek jesz­cze nie widziałem.

DRM

22. paź 2010

— Wszystko ta sama sieczka — mruk­nął pod nosem, sam do sie­bie, odkła­da­jąc kolejną płytę na półkę.

Dopiero po chwili wyło­wił z gąsz­czu sza­rych, zastęp­czych okła­dek sin­giel, o który mu chodziło.

— Dzień dobry, chcia­łem dzie­sięć kopii tego — rzu­cił przy­jaź­nie w stronę kasjerki.

— Dzie­sięć? — Choć nadal uśmiech­nięta, dziew­czyna zro­biła zdzi­wioną minę. — Zwy­kle ludzie biorą trzy — zaczęła wymie­niać — na kino domowe, na iPoda i na komputer…

— Cóż, mówią na mnie Rock, jestem didże­jem — wypo­wie­dział te słowa z dumą, poda­jąc dziew­czy­nie pla­sti­kową kartę RIAA.

— Łał, to cudow­nie! Pro­szę. — Podała mu papie­rową torbę z pły­tami. — Numery seryjne płyt zostały przy­pi­sane do two­jej karty. Kolejny prze­gląd licen­cyjny two­jej karty w kwiet­niu. Czy mogę zain­te­re­so­wać cię czymś z naszej oferty specjalnej?

— Nie, dzięki.

Gdy wypo­wia­dał te słowa poczuł wibra­cje w wewnętrz­nej kie­szeni kurtki. Pró­bo­wał szybko scho­wać pakiet sin­gli do kie­szeni, ale było już za późno. Tele­fon zaczął dzwo­nić. Popa­trzył jesz­cze zre­zy­gno­wa­nym wzro­kiem na pul­su­jącą w rogu ekranu liczbę. Pozo­stało mu sie­dem odtwo­rzeń dzwonka. Pamię­tał kiedy wpro­wa­dzono te restryk­cje. Jeden ze zna­nych woka­li­stów w publicz­nym wywia­dzie przy­znał się, że usta­wił hit swo­jej kapeli jako dzwo­nek, dzięki czemu nie musi sam sobie pła­cić za jego słu­cha­nie. Sena­to­rzy RIAA byli wście­kli, kon­gres zmie­nił ustawę w jeden week­end, nie chcąc dopu­ścić do sytu­acji, kiedy mło­dzież pój­dzie w ślady swo­jego idola. Ode­brał rozmowę.

— Robert, czło­wieku, dopro­wa­dzisz mnie do ruiny. Czemu nie odbie­rasz zwy­czaj­nie, kiedy to ja do cie­bie dzwonię?

— Cześć Rock, wybacz, ale zdją­łem na chwilę słu­chawki, a wiesz prze­cież, że mój dzwo­nek nie ma licen­cji na publiczne odtwa­rza­nie. Jak tam zakupy, gotowy na dzi­siej­szy show?

— Taa, wiesz, że nigdy nie zawo­dzę. Wła­śnie kupi­łem ostatni sin­giel, to będzie praw­dziwa wisienka na tor­cie. W sumie mam już na wie­czór cztery godziny muzyki.

— Będziesz coś mik­so­wał na żywo?

— Na pewno, ale jesz­cze nie wiem, ile. Chcemy prze­cież jesz­cze coś zarobić.

— Dobra, to nie prze­szka­dzam, do–zo wieczorem.

— No to strzałka, tylko się nie spóźnij.

Minął róg sklepu i wsiadł do samo­chodu. Zapa­lił sil­nik i z tru­dem powstrzy­mał chęć wpa­ko­wa­nia jed­nego ze świe­żych nabyt­ków w szcze­linę odtwa­rza­cza. Zamiast tego włą­czył radio i w towa­rzy­stwie naj­now­szych infor­ma­cji z życia gwiazd ruszył w stronę domu. Pod­eks­cy­to­wany zbli­ża­jącą się imprezą pod­śpie­wy­wał w rytm muzyki z rzadka poja­wia­ją­cej się w prze­ry­wa­ją­cych audy­cję reklamach.

– ❧ –

Wie­dział, że jest gotowy. Czuł, jak każdy mię­sień drga z pod­nie­ce­nia. Zatrzy­mał auto pod klu­bem, na par­kingu dla vip–ów i ponow­nie przej­rzał kufe­rek z pły­tami, po raz ostatni zamie­nia­jąc nie­które z nich kolej­no­ścią. Pew­nym kro­kiem pod­szedł do drzwi dla wyko­naw­ców. Odru­chowo podał pla­stik kar­kowi w nieco przy­cia­snym garniturze.

— Może pan wejść. Karta ważna do kwietnia.

Zamie­nił jesz­cze parę słów z mena­dże­rem klubu i udał się do baru po „jed­nego na rozpęd”.

Pół godziny póź­niej wycho­dził już na scenę. Czuł pul­su­jącą adre­na­linę, kiedy oświe­tle­nio­wiec wska­zał go reflek­to­rem. Ujął w rękę mikro­fon i słowa popły­nęły same.

— Jak się bawi­cie, Nowy Yorku? — Pocze­kał, aż ucichną wrza­ski. — Jak pew­nie wszy­scy wie­cie, jestem Rock. — Wzro­kiem odna­lazł wśród widowni poznaną tego poranka kasjerkę. — Obok mnie stoi pan Miles Wel­les z komi­sji RIAA, który będzie czu­wał nad dzi­siej­szą imprezą. Za trzy minuty włą­czymy sys­temy prze­ciw­dzia­ła­nia nagry­wa­niu, osoby z apa­ra­tami słu­cho­wymi pro­simy o opusz­cze­nie sali. A teraz przy­go­tuj­cie się, bo dziś wie­czór damy czadu!

zsh + git

15. paź 2010

Brian Car­per opu­bli­ko­wał nie­dawno bar­dzo prak­tyczny spo­sób na pre­zen­ta­cję stanu sys­temu kon­troli wer­sji w zsh. Poni­żej waria­cja na modłę domyśl­nego wier­sza pole­ceń w PLD:

zsh + git

autoload -Uz vcs_info

zstyle ':vcs_info:*' stagedstr '%F{green}∙'
zstyle ':vcs_info:*' unstagedstr '%F{yellow}∙'
zstyle ':vcs_info:*' check-for-changes true
zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat '%b%F{1}:%F{11}%r'
precmd () {
    if [[ -z $(git ls-files --other --exclude-standard 2> /dev/null) ]] {
        zstyle ':vcs_info:*' formats ' %F{green}%b%c%u%f'
    } else {
        zstyle ':vcs_info:*' formats ' %F{green}%b%c%u%F{red}∙%f'
    }

    vcs_info
}

setopt prompt_subst
PS1='[%n@%m %~${vcs_info_msg_0_}]$ '
Creative Commons Attribution-NonCommercial-ShareAlike 2.5 Poland
This work by Patryk Zawadzki is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 2.5 Poland.
cheap online pharmacy