Papa Windows, nie będę płakał

napisane przez wiktor, 19:49 06-19-2008

W ostatnie wakacje z dobrze skonfigurowanego Windowsa XP przerzuciłem się na Maka. Nigdy za bardzo nie narzekałem na Windowsa. U mnie działał, co nie było chyba częstym zjawiskiem. Od jakiegoś czasu wzbiera się we mnie frustracja, kiedy patrzę wstecz na moje poprzednie życie ;). Ponieważ obecnie jestem w trakcie pisania magisterki to posiadam obecnie nieskończone pokłady wolnego czasu. Najwyższy czas z siebie wszystko wyrzucić.

windows-xp-ala-mac

Rzut oka na wygląd mojego Windowsa, żeby się przekonać, że Maki już mi wcześniej chodziły po głowie. Nie będę wspominał o ilości pracy, którą trzeba poświęcić, żeby z Windows XP zrobić sensowne środowisko programistyczne, co widać na obrazku wyżej.

Środowisko programistyczne

Kiedy programista siada do czystej kopii Windowsa, nieważne czy XP czy Vista, to pierwszym odruchem jest (a przynajmniej powinno być) zainstalowanie Cygwina. Czynność wręcz obowiązkowa i nikt nie mnie przekona, że ponieważ mamy cudowne IDE to już nic nam nie potrzeba. Naprawdę samo IDE wystarcza? Naprawdę, naprawdę?

W takim razie prosty test: Jak policzyć liczbę linijek kodu w projekcie? (najlepiej na konsolce oczywiście) Pamiętam, że podczas pisania Zespołowego Projektu Programistycznego (można patrzeć na to, jak na licencjat) na UW ciągle z kolegami sprawdzaliśmy, ile już linijek kodu mamy. No bo 20 tysięcy to był dopiero porządny wynik :).

Wracając do Cygwina. Mimo że sprawuje się on znakomicie to jednak estetyką on nie powalał.

cygwin

Jest po prostu brzydki i zawsze on będzie tylko imitacją konsolki unikowej. Tym samym przechodzę do kolejnej rzeczy, z jaką chce się rozprawić.

Natywne aplikacje

Aż nie wiem, od czego zacząć. OK, pokopię leżącego, czyli Vista. Nie będę się przecież czepiał, że okienka z edycją zmiennej środowiskowej nadal nie można rozciągnąć, co doprowadza do szału. O masowej adopcji WPF także nie będę wspominał. Przytoczę tylko kawałek postu pt. Where are the native Vista apps?, gdzie Eric Burke pisze:

Vista supports hardware-accelerated graphics. WPF seems to support really cool things like vector-based UIs. […]

How can Microsoft expect third parties to develop Vista-specific apps if the bundled utilities (chodzi o Paint i Notepad) don’t even take advantage of Vista features? This is incredibly hard to understand.

Good luck, Microsoft. I’m typing this on my new MacBook Pro, and it looks like I have plenty of native Cocoa apps from which to choose.

Wcześniej brak w pełni natywnych aplikacji mi nie przeszkadzał. Ale odkąd przesiadłem się na Maka dostrzegłem ich urok. Spójność wyglądu systemu operacyjnego i aplikacji jest bardzo miła dla oka oraz nie rozprasza. Dopiero teraz zrozumiałem istotę i potrzebę stworzenia biblioteki SWT, na którym oparty jest Eclipse. Aplikacje oparte na SWT będą lepiej prezentować się niż konkurencyjne napisane w Swingu. Sam pisałem aplikacje Swingowe (np. Symulator Sieci Petriego). Dlatego wiem, ile energii i pracy trzeba włożyć, żeby aplikacja napisana w oparciu o Swinga ładnie wyglądała. A tak poważnie to czy aplikacje desktopowe przeznaczone dla zwykłego użytkownika powstają w Javie, w Swingu? Poważnie? :)

Przyjazny system dla programisty

W Cupertino udało się stworzyć system, który nie ssie. Globalny, systemowy słownik dostępny w każdej aplikacji (tak, tak, jest to bardzo ważne), ujednolicony system notyfikacji poprzez aplikację Growl, czy innowacyjne pomysły na interakcje z użytkownikiem jak Quicksilver to tylko kilka przykładów małych rzeczy, które cieszą na Maku. Przy okazji to jeśli ktoś jest zainteresowany, czym jest Quicksilver to skromnie polecam swoją prezentację o Quicksilverze.

Powszechne w Polsce skojarzenie dotyczące Maków jest tragiczne :), ale mimo to trzeba robić coming out i łamać te stereotypy :). Więc czas na głupiutkie argumenty. Zacznijmy od konferencji i dużych firm. Nie ważne, czy spojrzy się na zdjęcia z RailsConf czy z JavaOne, to zawsze Maki tam przeważają. W Google’u 6 tysięcy na 20 tysięcy pracowników wybiera Maka. Jeszcze nie przekonany? :)

Papa Windows!

JAVArsovia 2008 - II edycja Konferencji Java grupy Warszawa JUG

napisane przez wiktor, 22:36 05-23-2008

31 maja 2008 w godzinach 9:00 - 19:00 w budynku Wydziału Biologii Uniwersytetu Warszawskiego przy ul. Miecznikowa 1 Warszawska Grupa Użytkowników Technologii Java (Warszawa JUG) oraz osoby zaprzyjaźnione (PJUG, Szczecin JUG, Trójmiasto JUG, Poznań JUG, Wrocław JUG) zapraszają na najciekawszą konferencję javową w Polsce - JAVArsovia 2008.

Motto konferencji: Miłośnicy Java dla miłośników Java aka Ciekawie o Javie.

Podczas 1-dniowej sobotniej konferencji zaprezentowanych zostanie wiele różnych technologii javowych i szkieletów aplikacyjnych. Z 4 panelami, każdy z 3-4 prezentacjami pragniemy, aby konferencja była ciekawa technologicznie oraz odzwierciedlała nasze własne, lokalne doświadczenia z Javą. JAVArsovia 2008 to idealne miejsce, aby spotkać się z innymi praktykami technologii, nawiązać kontakty, porozmawiać o bieżących problemach (technologicznych) i poznać nowe narzędzia, które usprawnią Twoje projekty. Sądzimy, że udział w konferencji JAVArsovia 2008 pozwoli każdemu popróbować się z nowościami technologicznymi lub zgłębić już poznane.

Wstęp wolny! Dobra zabawa gwarantowana!

Rejestracja na konferencję jest bezpłatna acz obowiązkowa i trwa do 29 maja! Na zakończenie konferencji zaplanowane jest spotkanie podsumowujące JAVArsovię na Polach Mokotowskich. Liczba miejsc ograniczona, więc czym wcześniej się zarejestrujesz, tym większa szansa na udział w niej.

Poprzednia edycja JAVArsovia 2007 była prawdziwym hitem czerwca 2007 w Polsce i teraz na pewno również nim będzie. Mamy nadzieję zorganizować największą i najbardziej huczną konferencję Java w Polsce w 2008. Bądź jej częścią! Miłośnicy Java już czekają na Ciebie…

Zapraszam w imieniu Kapituły JAVArsovii 2008 i grupy Warszawa JUG!

Dashboard Widget: Słownik Polsko-Angielski, Angielsko-Polski

napisane przez wiktor, 10:53 05-12-2008

Mój poprzedni słownikowy widget dla iGoogle odniósł duży sukces. Dostawałem maile od ludzi, którzy zaadaptowali słownik dla iGoogle do Opery, Firefoksa, a nawet do Dashboarda (poprzez WebClip). Ponieważ sam jestem użytkownikiem Maka, postanowiłem napisać widget dedykowany dla Dashboard. Moim zdaniem wygląda on o niebo lepiej niż swój poprzednik dla iGoogle.

Moje wrażenia programistyczne są bardzo miłe. Wykorzystywałem do tego środowisko Dashcode, które miało swoją premierę wraz z Leopardem. Nie jest ono zbyt rozbudowane, ale bardzo dobrze się sprawdza dla małych widgetów. Trzeba dodać, że ma bogatą bibliotekę komponentów, które znacząco ułatwiają pracę. Słownik tak samo jak swój poprzednik bazuje na dict.pl.


» pobierz widget «

Możesz zobaczyć wideo, jak prezentuje się widget poniżej.

Aktualizacja:

  • dzięki Pawłowi Wrzeszczowi udało mi się wyeliminować mały błąd pod MacOSem 10.4,
  • owiecc zasugerował, żeby nowe wyszukiwanie było przewinięte, tj. po wpisaniu hasła owca i przewinięciu wyników na dół, a następnie po wpisaniu hasła krowa wyniki nie powinny także być przewinięte na dół,
  • kiedy nastąpi błąd spowodowany brakiem dostępu do Internetu lub dict.pl nie będzie chwilowo działał, pojawi się odpowiednia wiadomość.

JRuby #02 - Ruby rozmawia z Javą, Java rozmawia z Ruby’im

napisane przez wiktor, 17:44 05-09-2008

Krok drugi: integracja

W poprzednim poście opisywałem proces instalacji JRuby'iego tak, żeby korzystanie z niego było proste. Czas wziąć na warsztat integrację Ruby'iego z Javą i odwrotnie.

Ruby rozumie Javę

Kiedy JRuby interpretuje skrypt Ruby'iego to mogą tam być używane wszystkie klasy Javowe. Chcemy, żeby skrypt korzystał z naszej wcześniej utworzonej biblioteki w Javie? Nie ma problemu, dołączamy ją do CLASSPATH i możemy z poziomu Ruby'iego z niej korzystać. Integracja została przedstawiona na poniższych przykładach. Dołożyłem wszelkich starań, aby komentarze były wyczerpujące.

Uruchommy interakcyjną konsolę JRuby'iego: jruby -S jirb i następnie pobawmy się kodem:

RUBY:
  1. # Znane z Javy importowanie wygląda standardowo.
  2. # Niestety importowanie z gwiazdką nie działa, więc import javax.swing.* poczęstuje nas błędem.
  3. import javax.swing.JFrame
  4. import javax.swing.JButton
  5.  
  6. # Składnia Ruby'iego została zachowana dla obiektów Javowych, widać to w tworzeniu nowego egzemplarza JFrame
  7. # Warto zauważyć, że nawiasy są nieobowiązkowe. Poniższe wywołanie jest równoznaczne z JFrame.new("...")
  8. frame = JFrame.new "Ruby swinguje z Java"
  9.  
  10. # Styl kodowania Ruby'iego zostaje zachowany także dla metod. W Javie lubimyTakPisać, a w Ruby'im trochę_inaczej.
  11. # Poniższe wywołanie jest równoważne z frame.setSize(300, 300), które także byłoby poprawne.
  12. frame.set_size 300, 300
  13.  
  14. # Gettery i settery Javowe są dostępne także w odmianie Ruby'iego.
  15. # Poniższa linijka jest równoważna z frame.setAlwaysOnTop(true), które także byłoby poprawne.
  16. frame.always_on_top = true
  17.  
  18. button = JButton.new "Nacisnij mnie"
  19.  
  20. # Blok kodu zostanie w locie przekształcony w klasę implementującą interfejs ActionListener. Niezłe!
  21. # Jest to domyślne zachowanie JRuby'iego, jeśli parametrem jest interfejs z jedną metodą.
  22. # Standardowo w Ruby'im używa się wcięć z 2 spacjami.
  23. button.add_action_listener do |event|            
  24.   # Przykład getterów ala Ruby. Równoznaczne z event.getSource().setText("..."), które także jest OK.
  25.   event.source.text = "Nie naciskaj mnie ponownie!"
  26.   event.source.enabled = false
  27. end
  28.  
  29.  
  30. frame.add(button)
  31. frame.show

Czas poczęstować Ciebie czytelniku jakimś smakołykiem. Oto on:

RUBY:
  1. # Rozszerzenie klasy Javowej String o mechanizm missing_method, czyli
  2. # ta metoda zostanie wywołana, jeśli na obiekcie zostanie wywołana metoda, która
  3. # nie została zdeklarowana.
  4. JavaUtilities.extend_proxy "java.lang.String" do
  5.   def method_missing(symbol, *args)
  6.     puts "Kogo wolasz?"
  7.   end
  8. end
  9.  
  10. txt = java.lang.String.new "Ala ma kota"
  11.  
  12. txt.hmmmm_jak_brzmiala_nazwa_tej_metody?()  # => "Kogo wolasz?"

Java rozumie Ruby'iego

Ruby może zostać wpleciony w kod Javy na 3 sposoby:

  • poprzez Scripting API (wprowadzone z Javą 6, JSR 223, unifikacja silników skryptowych używanych w Javie), szczegóły: https://scripting.dev.java.net,
  • poprzez Beans Scripting Framework (standard wprowadzany przez Apache Jakarta), szczegóły: http://jakarta.apache.org/bsf,
  • bezpośrednio odwołując się do interpretera JRuby'iego.

Zajmiemy się tylko pierwszą opcją. Będziemy do tego potrzebowali opakowania silnika JRuby'iego dla javax.script, które znajdziemy tutaj (najlepiej wersję 1.1.3).

jruby-scripting-api

Powyższa grafika przedstawia zależności w Java Scripting API. Z naszego kodu będziemy odwoływać się wyłącznie do klas javax.script.*, żądać silnika JRuby'iego (jruby-engine.jar), który z kolei sam już będzie odpowiednio wywoływał interpreter JRuby'iego.

Czas podwinąć rękawy i trochę pokodować.

JAVA:
  1. import org.jruby.RubyHash;
  2. import javax.script.*;
  3. import java.util.List;
  4. import java.util.ArrayList;
  5. import java.util.Map;
  6. import static java.lang.System.*;
  7.  
  8. public class RubyInJava {
  9.  
  10.     public static void main(String[] args) {
  11.         // Od Java Scripting API żądamy silnik JRuby'iego
  12.         ScriptEngine rubyEngine = new ScriptEngineManager().getEngineByName("jruby");
  13.         ScriptContext context = rubyEngine.getContext();
  14.  
  15.         List<Integer> list = new ArrayList<Integer>() {{
  16.             add(1); add(2); add(3); add(4);  
  17.         }};
  18.  
  19.         // Do środowiska JRuby'iego dodajemy globalną zmienną list
  20.         rubyEngine.put("list", list);
  21.  
  22.         // Skrypt Ruby'iego, który będziemy wykonywać
  23.         StringBuilder script = new StringBuilder();
  24.         script.append("puts '--- Ruby ---'                                  ").append("\n")
  25.               .append("puts $list.inspect                                   ").append("\n")
  26.               // JRuby do kolekcji Javowych dodaje typowe metody Ruby'iego dla kolekcji
  27.               .append(" $list.each { |item|                                 ")
  28.               .append("   puts \"Element #{item}\"                          ")
  29.               .append(" }                                                   ").append("\n")
  30.               .append(" puts \"Suma: #{$list.inject { |sum, i| sum + i }}\" ").append("\n")
  31.               .append("\n")
  32.               .append(" $hash = { :ala => :ma, :co => :kota }               ").append("\n");
  33.  
  34.         // Wykonanie skryptu
  35.         try {
  36.             rubyEngine.eval(script.toString(), context);
  37.         } catch (ScriptException e) {
  38.             e.printStackTrace();
  39.             return;
  40.         }
  41.  
  42.         out.println("--- Java ---");
  43.  
  44.         // Pobranie zmiennej globalnej po wykonaniu skryptu
  45.         Object hashAsObject = rubyEngine.get("hash");
  46.         out.println("Klasa: " + hashAsObject.getClass());
  47.  
  48.         RubyHash hash = (RubyHash) hashAsObject;
  49.         for (Object o : hash.entrySet()) {
  50.             Map.Entry entry = (Map.Entry) o;
  51.             System.out.println(entry.getKey() + " => " + entry.getValue());
  52.         }
  53.     }
  54. }

Aby uruchomić powyższy kawałek kodu trzeba mieć w CLASSPATH: jruby.jar oraz jruby-engine.jar.

Powyższe przykłady ilustrują, że ludzie pracujący nad JRuby'im wykonali kawał dobrej roboty, żeby łączenie Javy z Ruby'im było bezstresowe dla developerów. Takie połączenie dwóch światów daje nam nowe możliwości: tworzenie mini-języków dla aplikacji Javowych, aplikacje Swingowe w Ruby'im, nie wspominając o Ruby on Rails, a dla Ruby'istów dostępny jest cały ekosystem Javy :).

JRuby #01 - Jak zainstalować, żeby się pobawić?

napisane przez wiktor, 21:27 04-29-2008

JRuby #01 - Instalacja

Ten post otwiera serię artykułów poświęconych JRuby'iemu, czyli implementacji Ruby'iego na platformę Javy. Nikomu raczej nie trzeba przedstawiać nikogo z tej pary :). Na warsztat weźmiemy JRuby 1.1.1.

Zacznijmy od instalacji. Wszystkie poniższe komendy shella można bez problemu wykonać na MacOSie lub Linuksie/Uniksie. Jeśli ktoś pracuje pod Windowsem to polecam zainstalowanie Cygwina. Zatem do dzieła!

Uwaga: dystrybucja JRuby'iego zostanie zainstalowana w ~/jruby.

BASH:
  1. # Upewnienie się, że jesteśmy w katalogu domowym
  2. cd
  3.  
  4. # Tworzymy katalog jruby/
  5. mkdir jruby
  6. cd jruby
  7.  
  8. # Pobieramy dystrybucję JRuby'iego 1.1.1
  9. wget http://dist.codehaus.org/jruby/jruby-bin-1.1.1.zip
  10. unzip jruby-bin-1.1.1.zip
  11. rm jruby-bin-1.1.1.zip
  12.  
  13. # Tworzymy jeszcze alias do skryptu uruchamiającego JRuby, który dodajemy do pliku .bashrc
  14. echo "export JRUBY_HOME=\"$HOME/jruby/jruby-1.1.1\"">> ~/.bashrc
  15. source ~/.bashrc
  16. echo "alias jruby=\"$JRUBY_HOME/bin/jruby\"">> ~/.bashrc
  17. source ~/.bashrc
  18.  
  19. # Przyda się jeszcze Ruby on Rails :)
  20. jruby -S gem install rails --no-ri --no-rdoc

Ponieważ JRuby może się kłócić z obecną na komputerze dystrybucją Ruby'iego (u mnie tak było) to zaleca się poprzedzanie wywoływania programów w ten sposób: jruby -S nazwa_polecenia, np. jruby -S gem list - wtedy nie kłóci się nam z poleceniem gem z standardowej dystrybucji Ruby'iego.

Dla mnie ciągłe poprzedzanie poleceń poprzez jruby -S ... jest żmudne wolałem skorzystać z wiki projektu JRuby, gdzie przedstawili ciekawy trick.

BASH:
  1. # Do dodania do .bashrc lub .bash_login - co kto lubi :)
  2.  
  3. for f in $JRUBY_HOME/bin/*; do
  4.      f=$(basename $f)
  5.      case $f in jruby*|jirb*|*.bat|*.rb|_*) continue ;; esac
  6.      eval "alias j$f='jruby -S $f'"
  7. done

Powyższy skrypt tworzy aliasy dla wszystkich poleceń np. gem, rails w postaci jgem, jrails. Prefiks j jednoznacznie mówi, o co chodzi.

Teraz czas na chwilkę zabawy.

# Zobaczmy, jaką wersję mamy
$ jruby -v
ruby 1.8.6 (2008-04-22 rev 6555) [i386-jruby1.1.1]

# Zabawy z konsolą jirb
$ jruby -S jirb
irb(main):001:0> out = java.lang.System.out
=> #<Java::JavaIo::PrintStream:0xe33255 @java_object=java.io.PrintStream@7dcc23>
irb(main):002:0> out.println "Hello World!"
Hello World!
=> nil

Tak zaopatrzeni możemy spokojnie wyruszyć na przygodę z JRuby'im. Niedługo kolejne artykuły poświęcone JRuby'iemu.

Prezentacja JRuby on Rails na bis w Krakowie

napisane przez wiktor, 15:13 04-19-2008

Już w najbliższy czwartek będę w Krakowie dawał prezentację o JRuby'im w ramach PJUG. Szczegóły wydarzenia tutaj. Gdzie, o której?

24 kwietnia 2008 (czwartek), godz. 19:00 - 20:30
Akademia Górniczo-Hutnicza
Al. Mickiewicza 30, sala 429 C2

Czego można się spodziewać? Będzie to odświeżona wersja mojego show o JRuby'im (prezentacja i prawdziwe kodowanie na żywo), które debiutowało podczas WarsJava'07. Przez ostatnie pół roku się dużo zmieniło i będzie to odzwierciedlone na mojej prezentacji:

  • będzie użyta najnowsza wersja Ruby on Rails 2.0,
  • architektura REST, czyli architektura zorientowana na zasoby,
  • ilość zmian w aplikacji RoR, żeby uruchomić pod JRuby dramatycznie zmalała,
  • sposób wdrażania aplikacji RoR na serwery aplikacyjne został uproszczony,
  • i oczywiście nie zabraknie AJAXa ;).

Zapraszam!

A czy Ty potrafisz dobrze kodować?

napisane przez wiktor, 15:48 02-29-2008

Myślałem, że zejdę, jak to zobaczyłem podesłany przez kolegę post na grupie pl.comp.lang.java:

Musze poprawic czyjs kod i pozmianach ktorych dokonalem zaczal mi leciec
dziwny wyjatek:

Config.PROFILERR[DO_INSERT[articleList]][Pocz±tek] Start.
14:49:11,245 INFO [STDOUT] java.sql.SQLException: NotImplemented
14:49:11,247 INFO [STDOUT] at pl.eo.core.sql.Connection.prepareStatement(Connection.java:134)
14:49:11,247 INFO [STDOUT] at pl.eo.apps.cms.sql.CommonSQL.Article_loadCategoriesForArticleAndVersion(CommonSQL.java:769)
14:49:11,247 INFO [STDOUT] at pl.eo.apps.cms.Article.loadByResultSet(Article.java:845)
14:49:11,247 INFO [STDOUT] at pl.eo.apps.cms.Article.loadByResultSet(Article.java:742)

poszperalem i znalazlem zrodlo wyjatku:

public PreparedStatement prepareStatement(String sql,int AutoGeneratedKeys)
throws SQLException {
throw new SQLException("NotImplemented");
}

zamienilem to na:

public PreparedStatement prepareStatement(String sql,int AutoGeneratedKeys)
throws SQLException {
throw new SQLException("Implemented");
}

ale nie pomoglo, dalej nie dziala. Ma ktos pomysl dlaczego?

Jest to lepsze niż motyw wstawiania nowych rekordów do bazy danych... poprzez dodawanie nowych kolumn (autentyk!).

Móżdżku, co będziemy robić w nocy?

napisane przez wiktor, 21:18 02-05-2008

Nie mogłem się powstrzymać :). Znalezione gdzieś w sieci...

Co będziemy robić w nocy?

Garść linków do debaty o językach dynamicznych i Scali

napisane przez wiktor, 21:28 01-24-2008

Dziś dość króciutko. Tylko linki, ale za to bardzo smakowite.

  • Can Dynamic Languages Scale?
    Notka na TheServerSide dotycząca niepowodzenia projektu Chandler wywołała bardzo ciekawą dyskusję. Treść niusa nie jest istotna, tylko komentarze. Znajdziemy tam wszystko: obrzucanie się błotem, argumenty ad personam, tezy niczym nie podparte, czyli genialną i kulturalną dyskusję ;). Uwaga! Występują tam celebryci ze światka developerskiego: Bill Burke i Cedric Beust. Nieprawdaż, że brakuje serwisu pudelek.developers.com? :)
  • Invasion Of The Dynamic Language Weenies
    Dość dobra rozprawa o językach dynamicznych o bardzo prowokacyjnym tytule. Dobra lektura - tylko troszeczkę stronnicza ;). Warto poświęcić trochę czasu na poczytanie odnośników z linkografii do wpisu.
  • The busy Java developer's guide to Scala
    Tytuł mówi sam za siebie. Ted Neward, znany gawędziarz na wielu konferencjach, barwnym językiem opisuje pierwsze kroki ze Scalą. Miła czytanka.

Blipuj bezpośrednio z Google Reader

napisane przez wiktor, 0:33 01-11-2008

Ostatnio zacząłem używać Blipa i na razie sprawdza się jako platforma do mikroblogowania. Wklejkę wyświetlającą moje aktualne blipy (czyli wpisy na Blipie) dodałem do panelu bocznego na blogu. Bardzo brakowało mi narzędzia, które umożliwiłoby mi blipować o ciekawych niusach, artykułach bezpośrednio z Google Readera. Napisałem skrypt Greasemonkey BlipFromReader, aby to ułatwić.

Jak używać? W Google Reader wybierz wpis, który chcesz wysłać do Blipa i naciśnij Shift+B. BlipFromReader przygotuje wpis składający się z tytułu wiadomości i linku.

BlipFromReader

Jak go wypróbować?

  • Zainstaluj Greasemonkey. Jest to dodatek do Firefoksa, więc on również jest wymagany.
  • Zainstaluj BlipFromReader (po prostu kliknij na link, jeśli masz już zainstalowane Greasemonkey).
  • Odśwież Google Reader, wybierz wpis i naciśnij Shift+B.

Blip został wysłany

Następny »


Wiktor Gworek Nazywam się Wiktor Gworek i jestem gospodarzem tego bloga.
Przeczytaj więcej o mnie »