zsh + git

Brian Carper opublikował niedawno bardzo praktyczny sposób na prezentację stanu systemu kontroli wersji w zsh. Poniżej wariacja na modłę domyślnego wiersza poleceń 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_}]$ '

Button kontra przeglądarki

Ku pamięci:

  • Firefox¹ ignoruje line-height.

  • Firefox¹ dodaje własny element z dwupikselowym paddingiem i pikselowym borderem:

    button::-moz-focus-inner {
        border: 0 none;
        padding: 0;
    }
  • Wszystkie przeglądarki domyślnie wliczają ramki i padding do rozmiarów elementu:

    button {
        box-sizing: content-box;
        -moz-box-sizing: content-box;
        -ms-box-sizing: content-box;
        -webkit-box-sizing: content-box;
    }
  • IE7 i starsze nie radzą sobie z automatyczną szerokością przycisków:

    button {
        overflow: visible;
        width: 0;
    }
    button[type] {
        width: auto;
    }

¹ Dotyczy ogólnie produktów Mozilli.

Tymczasem w biurze…

Uruchomiliśmy nową wersję serwisu Centrum Faktur!

Listę nowości opisałem już w podlinkowanym tekście, więc właśnie tam zapraszam zarówno spragnionych wiedzy, jak i miłośników mojej twórczości literackiej.

Kobiety i dary można podsyłać do mnie. Problemy, błędy, uwagi — tradycyjnie, na Burzę Mózgów.

Faktury przez API

Odkąd rozpocząłem współpracę z Mirumee, w listach od moich czytelniczek wciąż powtarzało się jedno pytanie — kiedy? W końcu zrobiłem jednak te badania, a blog to nie miejsce na dyskusje o moim życiu łóżkowym, dlatego dziś pomówimy o CentrumFaktur.

Co wybrałbyś zatem, gdyby zaoferowano ci body shot z ciała dowolnie wskazanej przez siebie kobiety¹ lub nieskrępowany dostęp do API pozwalającego szybko, łatwo i bezpiecznie wystawiać faktury z poziomu twojego programu?

¹ Chciałem tu napisać, że panie mogą sobie wybrać mężczyznę, ale w ten sposób zmniejszyłbym szanse na to, że ktokolwiek wybierze API.

Mamy cholerną nadzieję, że nie lubisz tequili, bo w stworzenie tego API zainwestowaliśmy już sporo czasu. Nie owijając w bawełnę, przechodząc do meritum, bez ogródek i zbędnych ceregieli, waląc prosto z mostu i nie lejąc wody przedstawiam dokumentację API CentrumFaktur.

Zdradzę przy okazji, że odnośnikiem tym dzielę się z wami nieprzypadkowo. Wiem bowiem, że przeczytacie, bez wyjątku, wszystko, co tylko napiszę. I będzie się wam podobało. To moja strona i ja tu ustalam zasady.

PIT 37

Przychodzi taki moment, kiedy nie da się już odwlekać rozliczenia podatków. Ja swoją deklarację postanowiłem złożyć dopiero dzisiaj. Nie obyło się bez przygód.

Linux x86-64

e-Deklaracje wymagają Adobe AIR. Adobe AIR nie obsługuje 64-bitowego Linuksa. Tyle.

Dane z poprzedniego roku (niezbędne do rozliczenia elektronicznego) udało się wydobyć ręcznie:

$ sqlite3 ~/.appdata/e-Deklaracje.*/Local\ Store/settings.dat 'SELECT xmlDocument FROM EDK_DECLARATIONS;'

Z Wine jest podobnie — jedyna wspierana architektura, to x86.

Linux x86

Adobe AIR 1.5 jest zjebany, robi w środku bardzo złe rzeczy (budowa plików .rpm z rozszerzeniem .deb i tym podobne) i nie działa nigdzie poza Fedorą.

Adobe AIR 2.0 instaluje się bez problemu, przy okazji psując uprawnienia katalogów z ikonami, plikami .desktop i typami MIME. Adobe Reader 9 instaluje się bez problemów. e-Deklaracje uruchamiają się, pozwalają na stworzenie profilu i w zasadzie tyle. Proces acroread zajmuje całą dostępną pamieć i moc procesora. Dziękujemy ci, Adobe.

Online

Ostatecznie rozliczyłem się w przeglądarce, za pomocą aplikacji pitroczny.pl¹. Polecam tę wersję — oszczędza nerwów, ma lepszy interfejs (nie wygląda jak zeskanowany PIT) i, przede wszystkim, działa.

¹ Korzystając z tego odnośnika przeznaczasz 1% podatku na Fundację Nowoczesna Polska.

Django: Pinax i Satchmo

Obiecywałem w skrócie przedstawić cuda, jakimi są oba projekty. Jak obiecałem, tak czynię.

Marketing kołem napędowym gospodarki

Oba projekty znałem od dość dawna z prasy, jaką zapewniają im deweloperzy i fani na wszelakich djangowych portalach, planetach i konferencjach. Na siłę używał ich nie będę — pomyślałem — ale może kiedyś się trafi okazja, to zobaczę, czym się tak wszyscy ekscytują. W bebechy nie zaglądałem, wiedziałem tylko, że jeden ma być uniwersalnym szkieletem dla wszelakich serwisów społecznościowych, a drugi klockami do budowy sklepów internetowych.

Bliskie spotkania I stopnia

Okazja się trafiła, choć nie taka, jak planowałem. Najpierw przyszło mi bowiem robić jedynie niewielkie poprawki we wdrożonym już serwisie opartym o Satchmo, później dopisać jakąś prostą aplikację do rozwijanej jeszcze społecznościówki, która do dzisiaj chyba nie dorobiła się ani wdrożenia, ani nawet nazwy.

Działać to działało, pod maskę nie bardzo miałem czas zaglądać. Dalszy kontakt sprowadzał się głównie do czytania samych superlatyw o owych — chciałoby się rzec — przebłyskach geniuszu inżynierii programowania.

Pinax — pierwsza krew

Do czasu. Jeden z kontraktów z Mirumee wymagał wbudowania w serwis podstawowych funkcji społecznościowych. Jednogłośnie zdecydowaliśmy się wypróbować Pinaksa.

Miesiąc później mieliśmy już własny fork, z którego systematycznie usuwaliśmy kawałki takiego kodu, że starczyłoby na doktorat z architektury oprogramowania. Obejścia na workaroundy, zaślepki na hackach. Widoki z pominięciem formularzy rozbierające request na zmienne i bez żadnej walidacji pakujące je do bazy. Widoki pozwalające na edycję cudzych obiektów, jeśli tylko znało się ich id. Aplikacje, które nie działały wcale, albo te działające częściowo, z resztą kodu wykomentowaną i otoczoną FIXME.

Jedno jest pewne, zmarnowaliśmy na to masę czasu i jeśli będę musiał do Pinaksa podejść drugi raz, to tylko po to, żeby ze strzelbą pod pachą wyprowadzić go na tyły domu.

Początek przygody z Satchmo

Całkiem niedawno zostaliśmy z kolei zakontraktowani przez firmę z UK, która specjalizuje się w budowie sklepów internetowych w Satchmo. Niestety programiści odeszli tuż po rozpoczęciu projektu i ktoś musiał zadanie skończyć. Chciałem poznać Satchmo, teraz miałem okazję. A dokładniej dwa tygodnie na przerobienie garści plików PNG z projektami graficznymi na w pełni działające wdrożenie.

Pierwsze dwa dni spędziłem na lekturze dokumentacji i doprowadzeniu kodu do działania na swojej maszynie. Szybko też okazało się, że Satchmo to taki sam zestaw klocków, jak Pinax czy — nie przymierzając — samochód. Oczywiście, można wymontować tylną kanapę i zmienić choinkę zapachową na lusterku, ale próba wyciągnięcia radia szybko pokazuje, że jest trwale przykręcone do kokpitu. Jakiekolwiek próby dopasowania sklepu do potrzeb sprzedawcy albo przypominają próbę ucharakteryzowania poloneza na ciągnik siodłowy z użyciem plasteliny, albo kończą się głęboką ingerencją w kod poszczególnych modułów.

I wtedy zaczęły się schody

Właśnie kontakt z modułami był pierwszym momentem, kiedy krzyknąłem WTF. Kiedy pierwszy raz miałem kontakt z Satchmo, poszczególne moduły i aplikacje mieszkały we wspólnej przestrzeni nazw satchmo. Okazuje się jednak, że ktoś wpadł na genialny pomysł zaoszczędzenia kilku literek i całość by działać musi zostać umieszczona bezpośrednio w ścieżce Pythona. Wielkie brawa za potencjalne konflikty nazw z innymi modułami Pythona oraz za zajęcie co bardziej oczywistych nazw dla lokalnych aplikacji projektu.

To jednak nie koniec, szybko okazało się, że dokumentacja to tylko ciekawostka, a jakiekolwiek pojęcie o działaniu całości daje dopiero lektura kodu. Tam można znaleźć prawdziwe perełki.

Miłe złego początki

Na początku było śmiesznie:

{% for product in products %}
    {% if forloop.first %} <ul>  {% endif %}
        <li>{% thumbnail product.main_image.picture 85x85 as image %}
        <a href="{{ product.get_absolute_url }}"><img src="{{ image }}" width="{{ image.width }}" height="{{ image.height }}" /></a>
        <a href="{{ product.get_absolute_url }}">{{ product.translated_name }}</a></li>
    {% if forloop.last %} </ul> {% endif %}
{% endfor %}

Oczywiście, zdarza się, że pierwszy i ostatni element listy występują gdzieś w środku, dlatego bezpieczniej sprawdzić wszystkie.

Powrót do przyszłości

Wkrótce okazało się, że system płatności dla niektórych operatorów wymaga dodatkowo podania daty wystawienia karty. Z tym, że data wystawienia i ważności oferują ten sam zestaw opcji: od stycznia bieżącego roku, do grudnia za cztery lata. Cóż, widać karty starsze niż trzy miesiące nie są zbyt popularne, za do zdarzają się w obrocie karty wystawione za dwa lata.

Działa doskonale, działa bez przerwy

A co powiecie na nieskończoną pętlę rekurencji właśnie w module płatności?

def confirm_info(request, template='shop/checkout/protx/confirm.html', extra_context={}):
    payment_module = config_get_group('PAYMENT_PROTX')
    controller = confirm.ConfirmController(request, payment_module)
    # ...
    controller.onForm = secure3d_form_handler
    controller.confirm()
    return controller.response

# ...

def secure3d_form_handler(controller):
    """At the confirmation step, protx may ask for a secure3d authentication.  This method
    catches that, and if so, sends to that step, otherwise the form as normal"""

    if controller.processorReasonCode == '3DAUTH':
        # ...
        return http.HttpResponseRedirect(redirectUrl)

    return controller.onForm(controller)

Ładnie, prawda?

Telekonkurs dla naszych widzów

Na koniec zagadka. Problem: podczas testów użytkownik opłacił za towar, ale na stronie z potwierdzeniem zamówienia pojawiła się informacja o nieudanej płatności. Rozwiązanie: okazuje się, że właściciel sklepu źle wypełnił pole na własny adres e-mail. Czy ktoś z was potrafi bez zaglądania w kod znaleźć logiczne powiązanie?

Otóż pole na e-mail obsługi sklepu nie jest typu EmailField i jest mu generalnie obojętne, jaką wartość się poda. System płatności zaś na koniec transakcji wysyła e-mail z potwierdzeniem na adres sklepu. W bloku o takiej konstrukcji:

try:
    self.response = dict([row.split('=', 1) for row in result.splitlines()])

    # ...

    return ProcessorResult(self.key, success, detail, payment=payment)

except Exception, e:
    self.log.info('Error submitting payment: %s', e)
    payment = self.record_failure(order=order, amount=amount,
        transaction_id="", reason_code="error",
        details='Invalid response from payment gateway')

To oczywiście nie koniec. W kodzie można znaleźć takie wynalazki, jak:

  • obiekt NOTSET, pełniący funkcję None;
  • aplikacja livesettings, umożliwiająca softcoding rzeczy, które powinny być w kodzie (niektóre z nich wymagają do działania restartu usługi, to się dopiero nazywa ironia);
  • bezmyślne zapychanie logów gdzie i czym popadnie;
  • i wiele, wiele innych.

Odpręż się, to nie będzie bolało

Nie mam pojęcia, jak oba projekty wyrobiły sobie jakąkolwiek renomę. Pinax jest zwyczajnie niegroźną kupą kompostu, którą należy omijać z daleka albo mieć potem pretensję do samego siebie. Satchmo z kolei operuje cudzymi pieniędzmi.

Czy nie byłoby lepiej zamiast chwalić się udanymi wdrożeniami (chyba, że jest to chwalenie się na zasadzie: nie wiem jakim cudem, ale się udało), zająć się testowaniem własnego kodu? Już nie mówię nawet o poprawianiu go, żeby przypominał coś napisanego w Pythonie, wystarczy, żeby działała więcej niż jedna kombinacja, zaś zepsute i nietestowane od miesięcy moduły zostały w stosowny sposób oznaczone.

Mówiąc w skrócie, jestem na nie.

Dla programistów: M+ MN Type-1

Cóż porabia w dzisiejszych czasach programista? pytacie mnie w rozlicznych listach, jakie nieustannie docierają na adres redakcji. Wydaje się, że najwierniejszymi fanami są pan Urząd Skarbowy oraz pan Zakład Ubezpieczeń Społecznych. Drodzy Urzędzie i Zakładzie, szukałem fontów.

Czcionek! — wyczuwam oburzenie rodzące się w głowie pana w drugim rzędzie, który po chwili jednak pąsowieje, przypominając sobie, że czcionką nazywamy fizyczny nośnik kroju. Taką, pardon, metalową wersję połówki ziemniaka — zupełnie nieinformatyczny temat, nieprawdaż?

Fontów szukałem w celach bardziej naukowych, niż artystycznych czy użytkowych, jednak poszukiwania te przyniosły dość nieoczekiwany rezultat. Postanowiłem mianowicie odświeżyć swoją znajomość z rodziną M+, którą zapewne wszyscy doskonale znacie.

Tu następuje dramatyczna pauza, dzięki której wszyscy słyszą, kto w pośpiechu nadrabia zaległości…

Teraz już wszyscy zdecydowanie kiwacie głową, dyskretnie zerkając, czy koleżanka przy biurku po prawej domyśla się prawdy, a ja wprawiam was w większe jeszcze zakłopotanie, przypominając, że chodzi o programistów. Postanowiłem mianowicie tytułowego M+ MN Type-1 użyć w charakterze systemowej czcionki o stałej szerokości. Efekt? Pierwsze objawy uzależnienia.

Zobaczcie zresztą sami (pionowa linia wyznacza granicę 80 kolumn):

Dla porównania Droid Sans Mono:

Toż to wygląda, jak moje pierwsze ATARI zakrzykną na widok drugiego obrazka ci bardziej spostrzegawczy, a słuszności ich słowom odmówić nie sposób. Idźcie przeto i krzewcie dobrą nowinę pośród ludu swego. Czyż nie zostało bowiem powiedziane poznasz programistę złego po rozlazłym foncie jego?

Styczniowe zmiany w Centrum Faktur

CentrumFaktur - Faktury i oferty. Lepiej.

Dzisiaj — dokładnie miesiąc po ostatniej aktualizacji — udostępniliśmy kolejną aktualizację CentrumFaktur. Między innymi pojawiły się faktury zaliczkowe, o które część z was prosiła.

Więcej informacji na blogu Mirumee. A teraz, jako że nadal nie jestem właścicielem CentrumFaktur, czas usiąść do kolejnego projektu.

Cmentarnie: GRUB i GRUB2

Wczoraj, za namową qwiata, zrobiłem kolejną przymiarkę do drugiego wcielenia GRUBa. Tym razem zakochałem się niemal i nie chcę za nic wracać.

Automatyka wykrywająca konfigurację PLD działa znakomicie, a po napotkanych dawniej błędach w okolicach obsługi LVM nie pozostał nawet ślad. Na poparcie swojego stanowiska wspomnę tylko, że dziś rano, pierwszy raz od lat, pozbyłem się partycji /boot. Dotąd musiałem trzymać osobną, 30-megabajtową partycję na ext2, gdyż pierwsze wcielenie GRUBa nie radziło sobie ani z xfs, ani z LVM.

Howto

Instalacja:

# grub-install /dev/sda
# grub-setup '(hd0)'
# update-grub

Po zmianie jądra:

# update-grub

Ten ostatni krok już niedługo stanie się zbędny.

Jeśli ktoś jeszcze zwleka, to naprawdę nie ma na co czekać. Oczywiście, są jeszcze użytkownicy LILO, ale ich szanujemy. Jeśli pozostałe projekty GNU będą rozwijać się tak prężnie, to są szanse na używalną wersję HURD jeszcze zanim przepełni się 32-bitowy znacznik czasu ;)

Logika rozmyta, czyli o godnym przyjmowaniu krytyki

Disclaimer: Na wstępie chciałem ostrzec, że tekst dotyczy moich kontaktów z InFaktem, który to serwis z racji umowy wiążącej mnie z Mirumee niektórzy mogą uznać za moją konkurencję.

Cenimy InFakt (i mówiąc my nie mam na myśli ja, właściciel CentrumFaktur, do czego jeszcze dojdziemy). Mamy również pełną świadomość tego, że sporo firm właśnie ich wybrało do wystawiania faktur. Udawanie, że jest inaczej, mijałoby się z celem. Tyle tytułem wstępu.

Pojawili się pierwsi użytkownicy CentrumFaktur i razem z nimi pierwsze życzenia. Zupełnie nie byliśmy zdziwieni, kiedy ktoś wskazał na API InFaktu, prosząc o dodanie możliwości importu danych. Dostałem link do dokumentacji, dostałem dane dostępowe do konta, zabrałem się do pracy.

Zaczęło się od dokumentacji, czy może raczej dokumentacji. Plik PDF ma bowiem 3,5 strony i przedstawia cały interfejs w pięciu prostych punktach. Akcent na słowo prostych pada celowo, gdyż autorowi udało się pominąć wiele jakże nudnych kwestii technicznych, skupiając się na szlifowaniu swego kunsztu literackiego.

Chciałem niniejszym nominować API InFaktu do następujących wyróżnień:

  • Pierwsza dokumentacja API w XML, która nie zawiera ani jednego znaku < — to zadziwiające, ale autorowi udało się opisać aplikację XML bez choćby wspominania jej schematu.
  • Pierwsza dokumentacja API, gdzie strukturę XML zapisano w postaci tablicy mieszającej PHP Rubiego — to również nie żart, spodziewam się, że wersja 0.7 w ramach dywersyfikacji wprowadzi również JSON i YAML.
  • Jedyna dokumentacja API, gdzie prawie wszystkie nazwy elementów zostały podane błędnie — autor, choć zapomniał o udokumentowaniu struktury, przytacza nazwy elementów w rodzaju <nazwa_firmy/>, zupełnie nie przeszkadza mu fakt, że w rzeczywistości element ten to <nazwa-firmy/>.
  • Jedyne API, które do dostępu wymaga, oprócz klucza, podania loginu i hasła — czemu nie chcemy używać loginu i hasła w dostępie do API? Aby w razie czego łatwo i bez ryzyka odciąć dany program. Zatem wprowadźmy klucze i wtedy wystarczy zmienić klucz, a autor aplikacji, nie znając loginu i hasła… wróć, o szit, o szit, o fak.

Zamiast sensownego opisu, mamy dokumentację przez implementację. Dokumentację postanowiłem zatem w skrócie nazywać doku. W skrócie od do kurwy nędzy. Cóż, przynajmniej nie użyli SOAP (którego to protokołu nazwa słusznie sugeruje rozkosze kojarzone ze schylaniem się pod prysznicem). Bywa i tak, damy radę. Rach-ciach-ciach i… dupa.

401 Unauthorized

No nie wierzę, że nie umiem w trzech linijkach zrobić Basic Auth.

Sprawdzam ponownie, kod wygląda ok — podać login i hasło-sklejone-z-kluczem do modułu autoryzacji, wywołać GET, wydrukować wynik (a potem napisać sobie samemu dokumentację schematu). Biorę przykład InFaktu, napisany w PHP (z własnym klientem HTTP, stworzonym w technologii Copiego-Paste’a, włącznie). Zmieniam login, zmieniam hasło, zmieniam klucz. Uruchamiam, dupa. Mam już dwie dupy i wciąż ani jednego klienta, żyć nie umierać.

Pytam na Blipie, tu zaczęła się prawdziwa przygoda. Zaczęło się dość sympatycznie:

Tak to jest jak konkurencja czyta API:-) Powiedz co dokładnie Ci nie działa

InFakt, Blip

Po chwili odbijania piłeczki (nie lubimy nieczystej gry) dowiedziałem się, że jestem właścicielem CentrumFaktur. Otóż nie jestem, jakkolwiek by się przy tym nie upierać, właścicielem Portfeo i CentrumFaktur jest Mirumee. Na pieczątce, którą mam przed sobą, stoi Mirumee Software, Mirosław Mencel. Ja najbliżej literki M byłem, gdy nadawano mi drugie imię Michał, którego jednak nie używam.

Wszelkie próby dogadania się na szczeblu technicznym (ze wskazaniem na fakt, że nie naruszam regulaminu InFaktu włącznie) spełzły na niczym. Dyskusja na poziomie a my i tak wiemy lepiej, Balcerowicz musi odejść.

Wreszcie rozmowa przeradza się w rasowy flejm ze stosowną argumentacją w komplecie:

Brawo!! Mamy pełny obraz :-) Przygotowujecie kopię Infakt, nasyłacie kolegów do czarnego pr i uważacie że infakt jest be. Bomba

InFakt, Blip

Otóż wierzcie mi Państwo, że w obliczu zastanego profesjonalizmu, czarny PR rozdaję całkiem charytatywnie. Trochę pokory, panowie. Faktycznie, InFakt mocno przyczynił się do powstania CentrumFaktur. Byłem przy tym, to wiem. A skoro wiem, to opowiem.

Pracowałem ci ja sobie spokojnie nad Portfeo, kiedy to zaistniała w ekipie Portfeo potrzeba regularnego wystawiania faktur VAT. Wobec tego Mirek bez zastanowienia (idąc za głosem rekomendacji) założył konto na InFakcie (w jakże doskonale zakamuflowanej domenie portfeo.infakt.pl, co dowodzi naszego przebiegłego szpiegostwa). Po paru próbach użycia okazało się, że serwis nie spełnia jego oczekiwań i zaproponował mi kontrakt na stworzenie alternatywy. Dwa podpisy później konto na InFakcie wyszło z użycia.

Ot i cała historia inspiracji, jakiej dostarczył nam InFakt. Historie o kopiowaniu interfejsu czy możliwości proponuję włożyć między bajki. Trochę pokory, do bajek wrócimy, kiedy w przyszłym roku InFakt udostępni moduł ofertowania. Co zaś się tyczy inspiracji, to wzorowaliśmy się na Ballparku i nie wstydzimy się tego zupełnie — wszak jeśli się uczyć, to od lepszych od siebie.

Koniec końców zdawało się, że wczoraj sytuacja się unormowała. API InFaktu zaczęło magicznie działać (bez zmian w kodzie z mojej strony), więc uznałem, że z administratora zeszło ciśnienie i nas odblokował. Dziś jednak cyrk zaczął się na nowo, a do mnie wpadły (między innymi) takie wiadomości:

Ujawniliśmy publicznie Wasze nieetyczne zachowanie. Próbujecie wykorzystać nasze API do transferu Klientów. Żałosne ale prawdziwe.

InFakt, Blip

Infakt udostepnił API publicznie, nikomu nie blokuje dostępu, nawet Wam, tym którzy szukają drogi na skróty w zdobywaniu Klientów

InFakt, Blip

Nie mam pojęcia, kto we wspomnianym wcześniej serwisie operuje kontem ^infakt, ale z całą pewnością nie przysługuje się wizerunkowi firmy. Gdybym był złośliwy, to napisałbym, że limit 160 znaków sugeruje, że może to być autor dokumentacji. Ale nie jestem, prawda?

Drogi użytkowniku ^infakt, spieszę poinformować, że twoja logika nie trzyma się kupy. W jakiż to sposób CentrumFaktur miałoby ukraść wam użytkowników? Emaksem przez sendmejla (potrójna ścianka ognia) zdobyć wszystkie loginy i hasła, wygenerować klucze API i dokonać migracji na siłę? No bo, proszę ja was, po mojemu to dane klientów i faktury są własnością firmy, a nie InFaktu i user ma prawo je sobie migrować gdzie chce.

Wersja dla opornych: użytkownicy muszą najpierw samodzielnie założyć konto w CentrumFaktur, następnie wpisać z własnej nieprzymuszonej woli dane do logowania i nacisnąć przycisk Importuj. Nikt tu nikogo pod pistoletem nie trzyma. Kiedy skończę pracować nad API CentrumFaktur, będziecie mile widzianym jego konsumentem.

Apeluję zatem: trochę dystansu. CentrumFaktur z pewnością daleko jest do ideału, ale nie widziałem, żeby Mirek z tego powodu naskakiwał na krytyków. Wasze API aż prosi się o sensowną dokumentację i pozbycie się loginów i haseł (co na Blipie sugerowałem równie grzecznie, co bezskutecznie). Mam również nadzieję, że pracownicy InFaktu będą łaskawi zejść wreszcie z moich pleców, bo wierzcie mi, że licytację na techniczne niedoróbki można kontynuować, ale nie przyjdzie to z zyskiem dla żadnej ze stron.