niedziela, maja 30, 2010

Jak szybciej znaleźć mniejszą i większą wartość? [opisowy tytuł, który niewiele mówi ;-)]

Optymalizacja to zło, ale jakbyście czasem musieli ;-) to dziś porada dotycząca szukania mniejszej i większej liczby. Na wejściu dostajemy 2 liczby typu double, na wyjściu chcemy dostać te same liczby, ale tak by były ustawione wg. wielkości. wejście: a, b wyjście: min(a,b), max(a,b) Pierwsze co przychodzi do głowy to:

 double c = Math.min(a, b); 
double d = Math.max(a, b);
a = c; b = d;
Jednak szybsze jest użycie takiego kodu:

 double c = a+b;
b = (a<b)?b:a;
a = c - b;
Ten drugi kod na wykonanie zużywa tylko 74% czasu potrzebnego na wykonanie pierwszego kodu. Zawsze to coś, jeżeli Twój kod spędza 100 sekund w ustalaniu która liczba z 2 jest większa, a która mniejsza to zawsze te 26 sekund można spożytkować na coś innego ;-) Oczywiście trzeba sprawdzić wszystko w swoich warunkach, mnie to pozwoliło na przyśpieszenie programu o jakieś 4-5% bez wyraźnego spadku jakości obliczeń. [Co nie ma do końca sensu, bo wystarczy małe "zachwianie" procesora, spowodowane włączeniem się innego procesu i cały zysk się w moim przypadku traci, ale to przez to, że najbardziej procesożerna część programu trwa około 22 sekund ;-)]


Podobne postybeta
Plus dla Scala, minus dla Groovy ;-)
OOo2GD 2.1.1 gotowe :-)
Kryzys istotności ;-)
Architektura
OOo2GD w liczbach ;-)

wtorek, maja 25, 2010

Spóźnialskie Google Latitude ;-)

Używam Google Latitude, fajna sprawa i czasem pomaga ustalić np. to o której godzinie się wyjechało z danego miejsca i inne takie :-)Działa to tak, że moje G1 co jakiś czas [tak koło 10 minut] przesyła moją pozycję do serwerów Google'a, akurat teraz pozycje ustala głównie na podstawie położenia nadajnika GSM z którego korzysta telefon [szczerze to nie wiem czy robi to tylko wtedy gdy nie widzi GPSów lub WiFi, czy może zawsze].Korzystam z 2 aplikacji Latitude, pierwszą jest historia, drugą publiczna plakietka lokalizacji, czyli mówiąc po ludzku mapka, którą widać z prawej strony bloga ;-)Z tego też powodu Google przysyła mi co tydzień przypomnienie, że udostępniam te dane. I tu ciekawa sprawa ;-) Robią to coraz później :-) Zaczęli w niedziele o godzinie 7:21 rano, a ostatnio [tj. dziś :-)] przysłali w poniedziałek o 22:50.Zrobiłem sobie wykres i wygląda ciekawie ;-) [jest w dniach, na osi x mamy numer próbki, na y czas, gdzie 0 oznacza 7:21 niedzieli, a 1 oznacza 7:21 poniedziałku [czyli 24 godziny później]].Już kiedyś widziałem coś podobnego, ale wtedy mieliśmy błąd w systemie [każde przysłanie nowych danych powodowało zadanie do bazy zapytania o maksymalny numer rekordu, co przy paru milionach rekordów zaczęło powodować problemy] i podobny wykres wskazywał jak rosła ilość retransmisji ;-)Ale z tego wykresu widać też, że jak dobrze pójdzie to najpóźniej za 81.3 tygodnia znów zacznę dostawać te powiadomienia w niedzielę około 7:21 ;-) [raczej wcześniej, bo to na pewno nie jest zależność liniowa :-) ale OpenOffice.org nie chce mi żadnej innej policzyć...... hmmm... a może by tak rozszerzenie do tego? ;-)]

Podobne postybeta
GAE zmienia ceny i darmową quota'ę... a ja zmieniam kod ;-)
Ciekawe czy ktoś zajmuje się &amp;quot;testowaniem&amp;quot; czy może &amp;quot;próbkowaniem&amp;quot; rynku nieruchomości? :-)
Kilka Androidów w domu... jak to jest?
EEEBateria ;-)
Android i lokalizacja. Czego używać zagranicą?

poniedziałek, maja 24, 2010

Sprawdzanie zdjęcia ;-)

Żywot człowieka niedoinformowanego bywa męczący ;-)Przedwczoraj, albo w piątek jeszcze, zobaczyłem zdjęcie które się komuś udało zrobić przedstawiające ISS i wahadłowiec na tle Słońca. Człowiekowi, który je zrobił udało się zarejestrować całe przejście ISS przez tarczę Słońca, co trwało całe pół sekundy!Zdjęcie robi wrażenie to sobie postanowiłem sprawdzić czy wymiary na zdjęciu i rzeczywiste się zgadzają :-)Pierwszy problem był taki na jakiej wysokości właściwie ta ISS lata, nie mogłem sobie tego przypomnieć i jakoś nie mogłem nigdzie znaleźć tej informacji, dlatego stwierdziłem, że policzę ;-)Jak orbita ISS ma być stabilna to powinna być taką na której przyciąganie ziemskie jest równoważone przez siłę odśrodkową.Siła odśrodkowa zależy od prędkości [dokładniej kwadratu] i promienia, zaś siła przyciągania zależy od odwrotności kwadratu promienia.Siłę odśrodkową liczymy z:
Fodśrodkowa(r) = mV2/r
Przyciąganie z:
Fprzyciąganie(r) = GmM/r2
Jak je porównamy to sobie możemy wyliczyć promień:
r=GM/V2
Prędkość ISS znam z Wikipedii i wynosi V=7706 m/s.Stałą grawitacyjną i masę Ziemi też można znaleźć, ostatecznie mamy promień orbity równy r=6705669.67 metrów. Niby fajnie, ale to jest odległość od środka Ziemi, a jednak ludź, który to zdjęcie zrobił był na jej powierzchni. Krakowskim targiem doszedłem do wniosku, że użyję średnicy równikowej Ziemi i w końcu wyszło mi, że wysokość ISS to jakieś h=330 km.No to teraz tylko "pomiar" wielkości stacji na tle Słońca [24 piksele, w porównaniu do 545 całego Słońca].Teraz dobrze znać wielkość kątową Słońca. Mnie się głupiemu w głowie zawsze tłukły 2 stopnie, ale po pierwszych obliczeniach mi się coś nie zgadzało [bo mi się stacja zrobiła długa na ponad 500 metrów ;-)] to sprawdziłem na Wikipedii i przyjąłem 32.5 minuty kątowej.A znając wymiary w pikselach można przeliczyć, że stacja miała wtedy 84.8 sekundy kątowej.Teraz już tylko trzeba sobie przypomnieć co to jest tangens ;-) [przypomniałem sobie, nie zajrzałem do Wikipedii :-)] i wiemy, że tak "na oko" tangens z naszych kątowych wymiarów stacji jest równy jej wymiarowi podzielonemu przez odległość. Jeśli przyjąć, że przejście miało miejsce wtedy gdy słońce było w zenicie to wyjdzie nam, że wymiary stacji to jakieś 135 metrów....W rzeczywistości ma około 100 metrów ;-)Wydaje mi się więc, że zdjęcie jest prawdziwe :-)


Podobne postybeta
Trygonometria trudna
Cena benzyny w górę, wydatki na paliwo w dół ;-)
ISS poraz kolejny :-) tym razem poprzedzona HTV :-)
Tramwaj uczy i wychowuje ;-)
Kosmiczne klocki :-)

sobota, maja 22, 2010

Buzz Troll Remover v0.3.2 zawędrował do galerii rozszerzeń Chrome ;-)

No i Buzz Troll Remover jest już w galerii rozszerzeń Chrome.
Oznacza to, że osoby, które instalowały wcześniejszej jego wersja powinny go odinstalować i zainstalować z nowego źródła [i znów dodać trollów do listy].
Od dziś updaty do nowych wersji dostępne będą tylko tym kanałem.
Co nowego w tej wersji [i w wersji 0.3.1 także ;-)].
Brzydki guziczek "hide" został zastąpiony przez ciut ładniejszy krzyżyk:Poprawiłem w nim też kilka wewnętrznych spraw związanych z przestrzeganiem zasad bezpieczeństwa na stronach HTTPS [głównie chodziło o to by unikać jak ognia eval() co też uczyniłem]. Ikonka Buzz Troll Removera wyświetla teraz także liczbę blokowanych przez nas osób.
W samym okienku konfiguracji zlikwidowałem pytanie nas czy chcemy usunąć daną osobę z listy trolli, podyktowane to było tym, że poprzednie rozwiązanie nie działało w Chrome niższych niż 6.
Buzz Troll Remover działa tak :-)
Na koniec reklama konkurencji ;-)
Takiej dla Firefoksa [choć nie zdziwię się jeśli znów będzie działać za jakiś czas na Chrome] czyli skrypty Greasmonkey o wdzięcznej nazwie TrollEyBuzz.


Podobne postybeta
Ewolucja Buzz Troll Remover'a ;-) - czyli nad czym teraz pracuję
Buzz Troll Remover v0.3 - potęga guzików
Buzz Troll Remover v0.1.1 :-)
Przybywa userów :-)
Szaleństwo kolorów - kolorujemy Google+ ;-)

piątek, maja 21, 2010

... &lt;- takie pewne niedomówienie.

Zwykle na blogu nie przeklinam, ale wkurwiłem się. Bo poniektórzy zaczęli uznawać, że skoro stworzyłem Buzz Troll Removera to jestem jakimś cenzorem.
Gówno prawda.
Nie słucham Radia Maryja bo gdybym to robił to albo umarłbym ze śmiechu albo z wkurwienia.
Nie czytam Naszego Dziennika z tych samych powodów.
Staram się nie oglądać Wiadomości na TVP1 z tych samych powodów.
Tu mogę sam wybrać czy chcę używać danego komunikatora.
Na Google Buzz nie mam tej możliwości. Dawno temu dotarło do mnie, że czasem po prostu nie warto dyskutować bo jak nie ma się chociaż jakiejś minimalnej wspólnej płaszczyzny to w najlepszym przypadku dojdzie się do etapu w którym po cichu będzie się myśleć "co za kretyn", w większości przypadków ktoś po prostu to powie.
Ze zwolennikiem kary śmierci mogę dyskutować, ale różnimy się w pryncypiach i nie dojdziemy do porozumienia, co najwyżej ustalimy protokół niezgodności.
To samo z osobą gorąco wierzącą.
NIE MAM ZAMIARU NIKOGO NAWRACAĆ NA SWÓJ SPOSÓB WIDZENIA ŚWIATA, w zamian chcę mieć możliwość unikania tego by ktoś mnie nawracał.
Ktoś kto przychodzi na mojego bloga wyraża świadomą chęć zapoznania się z moimi poglądami, które może uważać za totalnie kretyńskie, albo za wspaniałe, ale to jest wybór odbiorcy. Nie spodoba się to pójdzie stąd i nie będzie mnie czytał.
Najgorsze co może spotkać Twój komentarz na moim blogu [puki mnie nie wyzywasz] to po prostu zignorowanie.
Dyskusja powinna coś wnosić, a nie przypominać dwustronne obrzucanie ściany grochem.
Dlatego jak mam dosyć to staram się ignorować zaczepki.
Chcę mojego prawa do niesłuchania. Wolność słowa oznacza tyle, że każdy może głosić swoje poglądy. Ale nie oznacza nakazu słuchania wszystkich którzy chcą je głosić.
Ja czasem nie chcę, i wtedy mam np. Buzz Troll Removera, który broni mojego prawa do niesłuchania.
Jesteś zwolennikiem kary śmierci? Jesteś fanatycznym zwolennikiem podatku liniowego?
Dobrze, cieszę się, nie rozumiem Cię, próbowałem, ale nie rozumiem i uważam, że nie warto marnować czasu na przedstawianie po raz milion sto pierwszy argumentów przeciw. Lepiej po prostu machnąć ręką.
Ale nie, dla niektórych to że po prostu nie mam ochoty spędzać 2 godzin dziennie na wyłuskiwaniu jakichś ciekawych wypowiedzi ze strumienia z Buzza spośród szumu generowanego często przez 1 czy 2 osoby oznacza, że jestem cenzorem.
Trudno, z tym też będę żył.
Złość piękności szkodzi, a już na pewno sercu, a moje serce i moje nerwy są dla mnie ważniejsze. Za stres mi płacą, sam go sobie nie będę serwował.


Podobne postybeta
Dlaczego nie zgadzamy się na powszechny dostęp do broni?
Iran coraz bliżej....
Nienawiść
Na 95% jesteś ateistą conajmniej w 99.680511182108626198083067092652% ;-)
Robimy z telefonu/tabletu z Androidem serwer WebDAV ;-)

czwartek, maja 20, 2010

Dinozaur w domu ;-)

Miały być żale jak mi to źle bo mam mało czasu ;-) ale będzie o czymś innym :-)
Jakiś czas temu do mnie dotarło, że podstawy naszej cywilizacji opierają się na produktach życia. Bo albo powstały z czegoś co kiedyś żyło, albo zostały wyprodukowane przez coś co żyło.
Popatrzmy w koło. Co zobaczymy?
Przed sobą mam komputer. Komputer wykonany z plastiku plus trochę metali. Plastik to ropa, ropa kiedyś była czymś co żyło, jakimś dinozaurem czy innym skrzypem.
Metal żywy nie był, na szczęście ;-)
Siedzę na jakimś krześle, albo takim w którym jest dużo plastiku - czyli siedzę na martwym dinozaurze, albo jeżeli jest w nim dużo drewna, to siedzę na pniu, bo drewno kiedyś było częścią żywego organizmu. Jest tam jakiś materiał jako okładzina, i znów jak syntetyk to ropa i wracamy do dinozaura, jak jakaś tkanina naturalna, to bawełna albo coś podobnego, czyli produkt roślinki, nawet gdy jest to jedwab to wyprodukowały go owady.
Komputer stoi na biurku, znów drewno.
Nie licząc metalowych części większość, jeśli nie wszystko co nas otacza jest produktem życia. Dopiero w większości domów ściany się wyłamują, to samo podłoga [pod dywanem, który znów z dinozaura albo wyprodukowany przez roślinkę, albo pod parkietem z drewna] i sufit.
[dinozaur, roślinka i kamienie tłumaczą prawie wszystko co nas otacza ;-)]

Ubrania to znów albo syntetyki [czyli chodzimy w "skórze" z dinozaura ;-)] albo bawełna czy coś podobnego.
Buty, łózka, tapety czy spodnie także są produktami życia.
Jedyne chyba produkty, których używamy, a które nie są produktami czegoś żywego lub same nie żyły to metale i kamień.
To życie widać jakieś sprytne jest, potrafi tak zamotać atomy pobrane ze środowiska, że później się okazuje, że większość naszych wyrobów to pośrednio produkty życia :-)


Podobne postybeta
Dinozaury czają się wszędzie....
Dinozaur na UJ ;-)
O szukaniu dziury w całym [układzie ;-)]
Pożerany przez dinozaura
Czego brakuje koderom ;-)

środa, maja 19, 2010

A różne takie...... czyli Fork-Join w JDK7, Azule i podobne :-)

Z serii rzeczy dziwnych, ciekawych i tajemniczych.
W JDK7 dodadzą bibliotekę czy raczej framework Fork-Join pozwalający na łatwiejsze pisanie aplikacji, które mogą skorzystać z wielowątkowości. To taki odpowiednik Google'owego MapReduce.
I tu ciekawostka, większość przykładów w sieci pokazujących jakie to fajne jest Fork-Join używa w środku metody forkJoin(), której nie ma w wersji Fork-Join która jest dostępna w obecnych wersjach JDK7 :-)
Jak zauważyłem w swoich testach, dobrze forkJoin() zastępuje wywołanie na przekazywanych do forkJoin() taskach najpierw fork(), a później helpJoin().
Ogólnie będzie to chyba fajna zabawka, chociaż "cały ciężar" spada na programistę, bo ktoś musi stwierdzić czy w ogóle da się dany algorytm zrównoleglić ;-) Bo nie wszystko, albo nawet wiele rzeczy, trudno zmienić na działanie wg. zasady dziel i zwyciężaj.
Przydałaby się jakaś dobra dokumentacja, albo dobry tutorial.
Ta fajna zabawka Fork-Join ślicznie działa na Azule :-) Wczoraj miałem szkolenie/wykład z Multi-core programming in Java i pod koniec prowadzący pokazał nam zabawkę jaką mają w laboratorium :-) Czyli "serwer" Azule, z 2 procesorami po 54 core'y każdy, czyli łącznie 108 procesorów, z których 100 dostępnych jest dla aplikacji w Java'ie.
Wszystko działa tak, że w systemie [przykłady były pokazywane na Linuksie jako maszynie skąd "startowały" programy] trzeba było wskazać, że chcemy używać maszyny wirtualne Azule, a nie np. Sunowskiej, po czym program odpalało się przy pomocy tej Azulowej maszyny i po chwili wszystko ślicznie działało na 100 procesorach Azule :-) Konfiguracja którą nam pokazywano to jedna z mniejszych [druga od końca] czyli 108 core'ów i tylko 96GB RAM :-)
Robi wrażenie. Taki serwer obliczeniowy.
Jak już przy Java 7 jestem, to takie pytanie. Android i jego Dalvik to taka dziwna Java, z innym bytecodem. Jeśli chodzi o ficzery języka to jest to Java 5/6, jeśli chodzi o "pośredni" etap bytecodu Java'owego to akceptuje Java 6.
W Java 7 wchodzą nowe ficzery języka, z których jak mniemam, ale to tylko przypuszczenie, część będzie związana z całkiem nowymi bytecodami [co najmniej chyba te rzeczy związane z językami dynamicznymi, a może też domknięcia].
Stąd moje pytanie, kiedy Android/Dalvik staną się kompatybilne z tymi nowymi ficzerami Java'y? I czy będzie to oznaczało kolejną zmianę wersji Androida? :-)
A jak Android to mój widget do Androida nabiera kształtów :-) Okazało się też, że Layouty w Androidzie nie są takie trudne. Jak na razie bazuję głównie na LinearLayout, którego największą tajemnicą, której nie znałem jest to, że może pracować w trybie vertical lub horizontal :-) to znacznie ułatwia :-)
Jeszcze o Androidzie, w Euro można kupić HTC Desire za 1769 złotych :-) ktoś mi chce zasponsorować? :-) [sam na razie nie mam zamiaru wydać 1769 złotych na telefon, ale jakby się okazało, że dostanie Androida 2.2 to się będę poważnie zastanawiał ;-) Chociaż chyba i tak wolałbym Nexus One, może ciut gorszy, bo nie ma radia i Sense UI, ale Google będzie chyba do niego częściej system wypuszczać]
Wracając do tego Multi-core programming in Java. Dwie konstatacje, pierwsze to to, że bardzo dobrze robię, że zaglądam w kod JDK. Tam się można wiele nauczyć i dostrzec geniusz ludzi, którzy je pisali. Np. taka klasa ConcurrentHashMap jest genialna, już sam pomysł by do zmniejszenia ilości potencjalnych konfliktów między wątkami użyć większej ilości HashMap zasługuje na pochwałę :-)
Konstatacja druga jest taka, że chociaż o wielowątkowości wiem pewnie więcej od 80-90% programistów Java'y to jeszcze dużo muszę zrozumieć :-) Chociaż z plusów muszę sobie przyznać, że po jakimś czasie dotarło do mnie samego, że jak się pisze cache współpracuję z bazą danych to dobrze by było żeby obiekty z danymi obsługiwały metodę clone() bo wtedy jest to "ciut" bezpieczniejsze ;-)
Z życzeń: mogłoby przestać padać.


Podobne postybeta
Azule i Android - przyszłość Java'y?
No i z lambdy nici
Poprawiamy JDK7 ;-)
Tnę i przerabiam na mniejsze, czyli nieprzewidziane skutki refactoringu
Wyznania programoholika ;-)

wtorek, maja 18, 2010

Buzz Troll Remover v0.3 - potęga guzików

Dokodowałem właśnie 2 rzeczy do Buzz Troll Removera, pierwszą jest brzydki guziczek "hide", który będzie się pojawiał przy wszystkich osobach z Buzza, po jego kliknięciu dana osoba zostanie wrzucona na listę Trolli.

Guziczek wygląda mniej więcej tak:

Po kliknięciu tego guziczka użytkownik zobaczy pytanie czy aby na pewno chce delikwenta wstawić na listę osób, których komentarze na Buzzie będą ukrywane:

[jak ktoś jest uważny, to zauważy, że powyższe 2 rysunki i tekst między nimi bezczelnie ukradłem z jednego z wcześniejszych wpisów ;-)]

Druga zmiana widoczna jest na liście trolli, już nie mamy tam listy linków, a listę nazw profili trolli, które jednocześnie są linkami do ich profili, z guziczkami unblock [i jak słyszałem nie wszędzie unblock działa :-(].

Wygląda to mniej więcej tak:

Gdy odblokujemy trolla to znów jesteśmy pytani czy aby na pewno tego chcemy i w razie czego wszystkie wcześniej skrzętnie ukryte [lub zastąpione przez informację o ukryciu] posty wrócą na swoje miejsce.

Kto chce może sobie pobrać nową wersję Buzz Troll Remover v0.3, na wszelki wypadek podaję też namiary na starszą wersję 0.2.1 jakby się komuś nie spodobała nowa :-)
W razie problemów pierwszą metodą może być odinstalowanie wtyczki, co prawda stracimy wtedy naszą trollliste, ale rozszerzenie ruszy z czystą kartą.


Podobne postybeta
Ewolucja Buzz Troll Remover'a ;-) - czyli nad czym teraz pracuję
Buzz Troll Remover v0.3.2 zawędrował do galerii rozszerzeń Chrome ;-)
Buzz Troll Remover v0.1.1 :-)
Ściana, czyli rozbijam się na onclick ;-)
Jak się rodzą Trolle?

Ściana, czyli rozbijam się na onclick ;-)

Zabawiając się z Buzz Troll Removerem dotarłem już do etapu na którym potrafię ukryć trollowe buzzy (trollbuzzy?) w taki sposób, że gdy użytkownik zdecyduje, że jednak odtrolluje danego delikwenta to jego komentarze znów się pojawią.

Niby super, ale jest jedno ale ;-) a mianowicie to, że wtedy nie działa guziczek "hide", który umiejscawiany jest przez BTR obok nicka użytkownika Buzza [buzzżytkownika? ;-)]. Próbowałem wielu sposobów i jak na razie odbijam się od ściany....

Guziczki tworzę tak:
var parent = b[i].parentNode;
var button = document.createElement("button");
button.innerHTML = "hide";
button.setAttribute("name",b[i].innerHTML);
button.setAttribute("link",b[i].href);
button.onclick=function() {
blockUser(this);
}

b[i].setAttribute("modifiedByBuzzTrollRemover","true");
parent.insertBefore(button,b[i].nextSibling);

Element b[i] to i-ty tag A na stronie spełniający jeszcze tam pewne wymogi.
Istotne jest to jak przypisywany jest kod do onclick.

Niestety użycie button.setAttribute("onclick","blockUser(this);") powoduje tylko tyle, że każde kliknięcie guziczka powoduje zgłoszenie na konsoli błędu mówiącego, że JavaScript nie może namierzyć funkcji blockUser(elem).

Samo kasowanie posta wygląda mniej więcej tak:
b[i].parentNode.parentNode.setAttribute("rBTK",b[i].parentNode.parentNode.innerHTML);
b[i].parentNode.parentNode.setAttribute("rBTKLink",b[i].href);
removed.push(b[i].parentNode.parentNode);
if (method*1==1) {
b[i].parentNode.parentNode.innerHTML="";
} else {
b[i].parentNode.parendNode.innerHTML="<span style='background:yellow;'>Post of "+b[i].innerHTML+" deleted by Buzz Troll Remover</span>";
}


Gdzie istotna jest pierwsza linia, która w atrybucie nad-nad-rodzica ;-) zapisuje treść kasowanego buzza.

Odnowienie Buzza wygląda tak elem.innerHTML = elem.getAttribute("rBTK");.

I problem jest taki, że onclick stworzone tak jak je tworzę w ogóle nie jest widoczne w tym co zostanie włożone do innerHTML, a jeśli użyję metody z przypisaniem stringa do onclick to co prawda jest widoczne w innerHTML, ale nie działa :-)

I pisząc to wpadłem na pomysł by jak zwykle rozwiązać problem przy pomocy oszustwa :-) Co dowodzi, że programowanie jest naprawdę sztuką oszukiwania.

A gdybyż tak "kopię" buzza, którą przechowuję, w momencie gdy będzie znów przypisywana do elementu potraktować wyrażeniem regularnym, które zamorduje wszystko od "<button" do "</button>", oraz wywali atrybut modifiedByBuzzTrollRemover? Wtedy mechanizm dodawania guziczków zobaczy taki wpis, stwierdzi, że wpis nie posiada guziczka i mu go doda....... :-)

Czyli jak dobrze pójdzie problem zrozumienia czemu onclick dodawany przez element.onclick="..." czy element.setAttribute("onclick","....") nie działa nie będzie ważny ;-) ważne będzie tylko napisanie odpowiedniego wyrażenia regularnego :-)


Podobne postybeta
IE suxx ;-)
Zasada numer 1: sprawdzaj oczywiste
Bookmarklet do robienia CSV z obligacjami i ich oprocentowaniem ;-)
Buzz Troll Remover v0.3 - potęga guzików
Go dla Java'owca ;-) odcinek 2 "kontenery dwa ;-)"

niedziela, maja 16, 2010

Programowanie jako sztuka oszukiwania ;-)

Programowanie to jednak sztuka oszukiwania ;-)Bawię się programowaniem Androida i próbuję w ramach tej zabawy napisać sobie widget do ekranu domowego, który będzie liczył biorytm [nie, nie wierzę w biorytmy, to bzdury, ale jak już kiedyś pisałem nadają się na widget bo są osobiste ;-)].Dziś dodałem mojemu widgetowi aktywność konfiguracyjną. I niby wszystko fajnie, ale miałem problem polegający na tym, że sam widget odrysowywał się wcześniej niż miałem dostęp do daty urodzenia podanej w aktywności...... to by się dało rozwiązać gdybym umiał z aktywności polecić widgetowi ponowne odrysowanie się, ale jak na razie to mi się nie udało. Dlatego w końcu poszedłem po rozum do głowy i zacząłem oszukiwać ;-)Zawartość metody updateBioWidget(Context, AppWidgetManager, int) odpowiedzialną za updatowanie wartości poszczególnych elementów widgetu wyrzuciłem do oddzielnej metody statycznej, która dostaje Context (czyli tak plus/minus informację o aplikacji), AppWidgetManager (czyli menadżera widgetów dzięki któremu można operować na samym widgetcie) i identyfikator widgetu (bo możemy mieć kilka takich samych widgetów, a nas interesuje dokładnie jeden) i wołam tą metodę w trakcie planowanych updatów, ale również w momencie gdy użytkownik kliknie Save w mojej aktywności konfiguracyjnej :-)Nie mogłem zmusić widgetu do odrysowania się, to po prostu odrysowuję go "na siłę", a żeby nie dublować kodu całą niecną działalność związaną z rysowaniem widgetu wyrzuciłem do metody statycznej :-)Sama aktywność konfiguracyjna wygląda tak:A widget nie poraża pięknością ;-)Ale w końcu działa mniej więcej tak jak chciałem ;-) Czyli mogę mieć kilka widgetów, z których każdy może pokazywać biorytm dla różnych dat urodzenia :-)


Podobne postybeta
Robimy widget do Windows 7 :-)
Wiedza magiczna
O tym w czym iOS jest lepszy od Androida
Clock JB+, czyli zegar z Jelly Bean 4.2 dla starszych Androidów
Głupi HTTPS...

czwartek, maja 13, 2010

SNPAW, czyli "Stosunkowo Najbardziej Przydatna Aplikacja Webowa" ;-)

Jeszcze jedno dziś ;-) czyli SNPAW = Stosunkowo Najbardziej Przydatna Aplikacja Webowa jakiej używam w pracy ;-)Oto ona:
Że sobie jaja robię? Nie, wcale nie.Po prostu w chwili obecnej najlepsze i najbardziej wygodne korektory ortograficzne mają przeglądarki WWW, i gdy trzeba czasem napisać jakiś tekst to najprościej napisać go w przeglądarce i później wkleić do dowolnej aplikacji :-)Bardziej zaawansowana wersja, taka w której można się nawet bawić w formatowanie ;-) tutaj:
A tu linki do obu "aplikacji":SNPAW w wersji standardowejSNPAW w wersji "delux" ;-)Wbrew pozorom warto sobie choć jedną z nich wrzucić do zakładek ;-)


Podobne postybeta
Takie tam przemyślenia i refleksje ;-)
Clarke
Noc
Koszmarny Garbage Collector ;-)
Spokój=Nuda

MD5 naprawdę ssie ;-)

Spać mi się chce, nie było dziś więc zbyt wiele kodowania [praktycznie w ogóle], a wpis będzie krótki ;-)MD5 jest do bani jeśli chodzi o "zabezpieczanie" haseł. Niby to wiedziałem, ale co innego wiedzieć bo się przeczytało, a co innego gdy człowiek sam się przekonuje ;-)Musiałem dziś coś zrobić z bazą w której hasła są trzymane w MD5, miałem też listę tych haseł i przypuszczenie, że niektóre z tych haseł nie pasują.Czyli wystarczyło zrobić tak, że każde ze znanych haseł przejechać MD5 i sprawdzić czy te w bazie są takie same...... nie chciało mi się pisać kodu do tego więc użyłem generatora hashy MD5 znalezionego w Internecie.Część hashy się nie zgadzała i tak z głupia frant zacząłem je wrzucać do Google'a. Na 3 próby w trzech przypadkach Google znalazło strony na których były "moje" hashe i hasła którym odpowiadały ;-)No to tyle jeśli chodzi o bezpieczeństwo MD5 ;-)

Podobne postybeta
Zaskoczenie
Przenośna wikipedia
Mały pomocny coś macOS'a
Znajomości
Lasertag, Windows 7 i kalkulator

środa, maja 12, 2010

Ewolucja Buzz Troll Remover'a ;-) - czyli nad czym teraz pracuję

Post z serii, ja już mam, a Wy dostaniecie jak uznam to za słuszne ;-)

Bawię się nadal Buzz Troll Remover'em, moim celem jest uczynienie go bardziej przyjaznym w użytkowaniu, a jak już się taki stanie to wrzucę go do repozytorium rozszerzeń Chrome :-)

Celem jest uczynienie blokowania łatwiejszym, jak na razie zdecydowałem się dodawać po prostu do każdego widocznego profilu guziczka z napisem "hide":

Po kliknięciu tego guziczka użytkownik zobaczy pytanie czy aby na pewno chce delikwenta wstawić na listę osób, których komentarze na Buzzie będą ukrywane:

Jeśli odpowie twierdząco to dane nowego trolla trafiają na listę trolli i Buzz Troll Remover zacznie ukrywać wszystkie posty danej osoby.

To wyżej już mam ;-)

Kolejne zmiany mają pojawić się w konfiguracji Buzz Troll Remover'a, listę niewiele mówiących linków zastąpić ma lista nazw blokowanych użytkowników [w razie gdy danego użytkownika "odziedziczmy" po poprzedniej wersji to będzie opisany jako =No Name= lub podobnie] z guziczkiem do skasowania ich z listy.
Użytkownicy którzy będą chcieli będą mogli użyć guziczka pod tą listą do zobaczenia obecnej listy linków [z małą zmiana, że każdy item będzie zbudowany w taki sposób link|nazwa blokowanego profilu].

Jak to będzie już gotowe to myślę, że wypuszczę wersję 0.3 i poważnie rozważę dodanie jej do repozytorium rozszerzeń ;-)
Ktoś ma jeszcze jakieś sugestie? :-)

Tak btw. ten model rozszerzeń w Chrome jest wielki ;-)


Podobne postybeta
Buzz Troll Remover v0.3 - potęga guzików
Buzz Troll Remover v0.3.2 zawędrował do galerii rozszerzeń Chrome ;-)
Buzz Troll Remover v0.1.1 :-)
Ściana, czyli rozbijam się na onclick ;-)
Szaleństwo kolorów - kolorujemy Google+ ;-)

poniedziałek, maja 10, 2010

Refleksje i serializacja w Java'ie - podstawy i obalanie mitów ;-)

OK, ten wpis już ma parę lat, stąd część o serializacji doczekała się nowszej wersji ;-)

Dziś o dwóch nie do końca zrozumiałych dla wszystkich aspektach Java'y, czyli o odbiciach aka refleksjach, i o serializacji.
Zacznijmy od odbić/refleksji.
Co to jest? Jest to mechanizm, który pozwala nam na dostęp do metod i pól dowolnych obiektów do których posiadamy referencje [lub klas jeśli chodzi o metody i pola statyczne], oraz na używanie obiektów których definicji nie znamy w momencie pisania naszego kodu.
Wszystkie zabawy z odbiciami odbywają się przez metody klasy Class.
Chcąc załadować definicję klasy, która jest na ścieżce ClassLoadera, a której typu nie znamy w momencie tworzenia kodu używamy metody forName(String). Najbardziej znanym przypadkiem gdy używamy tej metody jest ładowanie sterowników JDBC, które wygląda zwykle tak [tutaj przykład dla jakiegoś tam sterownika JDBC dla MySQLa]:
       Class.forName("com.mysql.jdbc.Driver");
Java ładuje klasę com.mysql.jdbc.Driver, ale w tym przypadku nie zapisujemy nigdzie referencji do obiektu klasy [nie robimy tego bo sterownik JDBC sam rejestruje się w mechanizmach JDBC].
Zwykle potrzebujemy jednak tej referencji, czyli wołamy kod taki jak ten:
       Class clasz = Class.forName("java.lang.String");
Od tego momentu w clasz mamy referencję do obiektu typu Class klasy String. Akurat w przypadku klas które znamy lub obiektów do których chcielibyśmy uzyskać dostęp łatwiej i rozsądniej jest używać pola class typu lub metody getClass() [obie rzeczy "dziedziczmy" po Object].
Czyli możemy to zrobić tak:
       Class clasz1 = Class.forName("java.lang.String"); // ładujemy przy pomocy forName
Class clasz2 = String.class; // używamy pola class
Class clasz3 = "Test".getClass();
Mamy w końcu obiekt typu Class dzięki, któremu możemy uzyskać dostęp do bebechów klasy :-)
Po pierwsze możemy poprosić Java'ę o listę metod publicznych dostępnych w danej klasie przy pomocy metody getMethods() lub listę metod (wszystkich, czyli publicznych, domyślnych, chronionych i prywatnych) zadeklarowanych w danej klasie [ale już nie nadklasie] lub interfejsie [ale nie "nadinterjesie" ;-) choć tu oczywiście będą same metody publiczne co wynika z tego czym są interfejsy] przy pomocy metody getDeclaredMethods(). Jako wynik dostaniemy tablice Method[]. W tablicy będą wszystkie dostępne metody, jeżeli klasa ma metody "przeładowane" to każda z tych metod jest jednym elementem w tablicy.
Możemy poprosić też o metodę o zadanej nazwie i zadanej liście parametrów, i znów by dobrać się do metody o dowolnej widoczności w naszej klasie używamy getDeclaredMethod(String,Class...), do dowolnej metody publicznej używamy getMethod(String,Class...).
Gdzie pierwszy String to nazwa metody, a Class... to tablica parametrów.
Np. pobranie metody compareTo(String) z klasy String wygląda tak:
       Class clasz3 = "Test".getClass();
Method method = clasz3.getMethod("compareTo",String.class);
Możemy w podobny sposób uzyskać też dostęp do pól [metody getFields(), getDelcaredFields() i adekwatne im metody z serii getField(String)], adnotacji, konstruktorów, etc.
Wróćmy do metod i obiektów.
Załadowaliśmy sobie definicję naszej klasy, teraz chcielibyśmy stworzyć instancję obiektu z tej klasy i zawołać sobie na nim jakieś metody. Jak to zrobić?
Tworzenie obiektu najprościej załatwić przez metodę newInstance(), której użycie jest równoważne wywołaniu konstruktora bezparametrowego. Stąd new String() jest równoważne String.class.newInstance(). [inna sprawa kto by wywoływał i po co konstruktor bezparametrowy String'a?]
Jeżeli chcemy użyć konstruktora z parametrami wygodniej nam będzie użyć metody getConstructor(Class...) lub getDeclaredConstructor(Class...). Jak zwykle wersja bez słowa declared w nazwie będzie działać tylko dla publicznych konstruktorów [konstruktorów nie dziedziczymy więc będą to tylko konstruktory publiczne w danej klasie], wersja ze słowem declared w nazwie pozwala uzyskać referencję do konstruktora o dowolnej widoczności :-)
Poniżej przykład wywołania konstruktora String(String):
 Constructor c = String.class.getConstructor(String.class);
Object obj = c.newInstance("Toster"); // nie znamy typu więc używamy Object
 System.out.println(obj);
Teraz gdy chcemy na tak utworzonym obiekcie wywołać jakieś metody musimy je pobrać przy pomocy pokazanych wyżej metod z rodziny getMethod.
Używamy do tego metody invoke(Object,Object...) z klasy Method:
 Method m = obj.getClass().getMethod("compareTo", String.class);
Object result = m.invoke(obj,"parametr");
System.out.println(result);
Wyżej najpierw pobieramy referencję do metody compareTo(String), a później wywołujemy ją w obiekcie obj i parametrem [akurat jest jeden] "parametr", wynik działania metody przypisujemy do zmiennej result.
W przypadku metod, czy pól prywatnych, domyślnych [gdy jesteśmy w innym pakiecie], czyli ogólnie niedostępnych wg. zasad widoczności Java'y musimy przed wywołaniem metody czy dostępem do pola zmienić jego widoczność [a możemy to zrobić przez odbicia :-)] przy pomocy metody setAccessible(boolean) danego cosia.
Jak znamy podstawy podstaw to trzeba o nich zapomnieć i wiedzieć, że wszystko wyżej jest złe i powinno być stosowane jak najrzadziej się da. W większości przypadków można używać odbić praktycznie bez ich używania ;-)
Często odbić chcemy używać do dodawania "wtyczek" do naszego kodu, znamy interfejs klasy której będziemy używać, nie mamy jednak na etapie pisania kodu dostępu do kodu, którego będzie używać nasza aplikacja jako wtyczek [co dość logiczne ;-)]. Wtedy zamiast używać tego wszystkiego co było wyżej najprościej zapewnić by wszystkie nasze klasy rozszerzały pewien interfejs, który posłuży nam do dostępu do "wtyczek", np. taki:
public interface Plugin {
onMessage(Message msg);
registerMessagesListener(MessagesListener);
}
Do tego każda nasza klasa powinna posiadać konstruktor bezparametrowy, wtedy praca z wtyczkami będzie wyglądała tak:
  Class clasz = Class.forName(pluginClassName);
Plugin plugin = (Plugin)clasz.newInstance();
plugin.registerMessagesListener(this);
Dzięki takiemu podejściu odbić używamy tylko do stworzenia obiektu. Zaletą jest to, że po pierwsze o wiele łatwiej będzie nam wykryć błędy [bo jeśli pomylimy się w nazwie metody kompilator albo środowisko powie nam o tym od razu, a nie dopiero w trakcie działania], a sam kod będzie szybszy.
Sam w ciągu mojego życia programistycznego widziałem 3 przypadki użycia odbić gdy było to konieczne, z czego w jednym przypadku generowało to strasznie dużo problemów, w dwóch działało i chyba działa nadal bardzo dobrze.
Z racji oszczędności miejsca nie pisałem tutaj o wyjątkach związanych z refleksjami, dlatego zachęcam do zabawy z nimi :-)

Trochę to dłuższe wyszło niż zamierzałem ;-) Dlatego o serializacji będzie krótko.
Serializacja i deserializacja.
Co to jest? Jest to mechanizm pozwalający na zapisywanie stanu obiektów i odczytywanie ich. Dzięki temu możemy np. zapisać stan obiektów, po czym w momencie kolejnego uruchomienia aplikacji wczytać ich stan.
Częstym mitem jest to, że serializacja i deserializacja [głównie o nią w micie chodzi] możliwe są tylko dla obiektów z konstruktorami bezparametrowymi. Jest to fałszywy mit, bullshit, nieprawda, głupota, etc.
Serializacja i deserializacja są mechanizmem całkowicie niezależnym od tworzenia obiektów przy pomocy konstruktorów. Konstruktory nie są NIGDY wołane w trakcie deserializacji obiektu (nie jest to do końca prawda bo gdy piszemy własne metody do serializacji to nic nie stoi na przeszkodzie by używać konstruktorów). Serializacja i deserializacja działa tylko i wyłącznie dla obiektów utworzonych z klas, które implementują interfejs Serializable.
Serializable to interfejs znacznikowy, który nie deklaruje żadnych metod.
Większość klas podstawowych z pakietu java.lang implementuje ten interfejs.
Dodatkowo serializacja i deserializacja wymaga by wszystkie pola inne niż prymitywy także implementowały interfejs Serializable lub były oznaczone jako transient.
Oznaczenie pola modyfikatorem transient mówi mechanizmowi serializacji by nie zachowywał wartości tego pola.
Dodatkowo mechanizm serializacji ignoruje pola statyczne.
Zapisanie stanu obiektu możliwe jest przy pomocy metody writeObject(Object) z klasy ObjectOutputStream, przykładowy kod może wyglądać tak:
 ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(str1);
W kodzie tym tworzymy strumień ObjectOutputStream na strumieniu w pamięci i zapisujemy do niego stan obiektu str1.
Odczyt jest równie prosty, używamy do niego metody readObject() z ObjectInputStream [tutaj uwaga, readObject() zwraca Object więc przy przypisaniu konieczne jest rzutowanie]:
 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
String str2 = (String)ois.readObject(); // bardzo ważne rzutowanie
Proste prawda? Nie do końca ;-) Bo jest jeszcze cały mechanizm pozwalający na to by samemu zapisywać i odczytywać obiekty. Nie zawsze musimy albo możemy skorzystać ze standardowych mechanizmów, czasem możemy mieć np. jako pole w naszej klasie, którą chcielibyśmy serializować [dokładniej obiekty z niej utworzone] które jest typu, który nie jest serializowalny, a na dodatek nie mamy możliwości dodania mu tej właściwości. W takim przypadku możemy stworzyć własny sposób serializowania obiektów.
Służą nam do tego trzy metody [których deklarację kradnę z JavaDoc'a ;-)]:
 private void writeObject(java.io.ObjectOutputStream out)
throws IOException;
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;
private void readObjectNoData()
throws ObjectStreamException;
Metody te dodajemy w klasie, która ma być serializowalna [najlepiej tej która używa pola z którym są kłopoty].
Kłopotliwe pole zaznaczamy jako transient dzięki czemu standardowy mechanizm serializacji zignoruje to pole.
W metodzie writeObject(ObjectOutputStream) musimy oprogramować zapisywanie stanu naszego obiektu, nie musimy pisać obsługi dla wszystkich pól, ponieważ do tego możemy wykorzystać standardowy mechanizm z jego metodą defaultWriteObject() [którą wołamy na przekazanym jako parametr strumieniu], która "pojedzie" standardem, my musimy oprogramować tylko nasze problematyczne pole lub pola.
Jak łatwo się domyśleć metoda readObject(ObjectInputStream) służy do odczytywania stanu obiektu, i tu znów możemy użyć domyślnego mechanizmu, który może obsłużyć wszystkie pola z którymi nie ma kłopotów. Do tego celu używamy metody defaultReadObject() [znów wołanej na parametrze]. Ważne jest tu by pilnować kolejności, czyli albo najpierw wołamy w trakcie zapisu defaultWriteObject(), a później zapisujemy stan pól specjalnych, i w trakcie odczytu najpierw wołamy defaultReadObject(), a później odczytujemy pola specjalne, albo robimy na odwrót najpierw pisząc/zapisując pola specjalne, a później używając defaultWriteObject()/defaultReadObject().
Ostatnią metodą jest readObjectNoData(), której przyznam się nigdy nie musiałem używać :-) więc mogę się w jej opisie oprzeć tylko na opisie z JavaDoc'a. W skrócie metoda ta jest wołana wtedy gdy "podnoszonej" klasy nie ma w strumieniu, który próbujemy odczytać...... ale przyznam, że nie udało mi się tego teraz oprogramować :-(
Są jeszcze dwie dodatkowe możliwe metody writeReplace() i readResolve(). Obie te metody służą do zastąpienia serializacji/deserializacj obiektu. Zamiast zapisywać nasz obiekt możemy przekazać do mechanizmu serializacji obiekt do zapisania przez zwrócenie go przez writeReplace(), a zamiast odczytywania obiektu ze strumienia możemy zwrócić obiekt przez readResolve().
Ponieważ ObjectOutputStream i ObjectInputStream można zbudować praktycznie nad wszystkimi typami strumieni to możemy serializować obiekty do pamięci, plików, skompresowanych plików, przez sieć, etc. [tak btw. serializowanie do GZIPOutputStream na strumieniu "sieciowym" nie działa, tak samo deserializacja ;-)].
Mechanizm serializacji/deserializacji w Java'ie nie jest jakiś szczególnie bystry, problemy więc mogą się pojawiać często i gęsto gdy np. zapiszemy obiekt utworzony ze starszej wersji klasy, a będziemy próbowali go odczytać nowszą. Czasem mechanizm serializacji może sobie z tym poradzić, a my wolelibyśmy by wygenerował w takim przypadku wyjątek. Do tego możemy użyć znów niewymaganego ;-) pola serialVersionUID. Ma to swoje zalety, ponieważ standardowo Java sama "doda" takie pole i wystarczy drobna zmiana w kodzie klasy [jakakolwiek zmiana!] i nie będzie możliwości zdeserializowania obiektu, który został zserializowany poprzednią wersją.
No i to by były podstawy podstaw serializacji.
Po co jej używać? Np. można na niej łatwo zbudować prosty protokół komunikacji między elementami naszej aplikacji stojącymi na różnych maszynach, zapewnić "trwałość" aplikacji przez okresowe zapisywanie stanu aplikacji lub jej kluczowych obiektów na dysk, do replikacji danych między różnymi instancjami aplikacji, do przechowywania kosztownych do wyliczenia wartości i do czego dusza zapragnie.

Jajx, długie wyszło ;-) 2 godziny pisania :-)


Podobne postybeta
Serializacja w Java'ie - revisited ;-)
Lenistwo w działaniu, "piklujemy" Androida ;-)
Czemu trzeba pomagać Jacksonowi? ;-)
Sortujemy JTable gdy się da ;-)
Sztuczki tropiciela błędów, part 2 ;-)

niedziela, maja 09, 2010

Matematyczne podstawy zakupu skarpetek ;-)

Sprawdzimy dziś lifehacka znanego pewnie wielu osobom ;-)
Lifehack mówi "kupując skarpetki kup kilka identycznych par, zamiast kilku różnych par, wtedy starczą na dłużej".
Uzasadnienie jest takie, że jeżeli masz 10 par identycznych skarpetek, to gdy potarga Ci się jedna z nich, to masz 9 par, ale gdy potarga się kolejna z pozostałych 19 skarpetek to tych par masz nadal 9, ogólnie liczba par to liczb skarpetek podzielona przez 2 i zaokrąglona w dół. Czyli masz średnio konieczne 2 awarie by wyeliminować daną parę skarpetek.
Gdy kupisz 10 różnych par, to wystarczy pojedyncza awaria skarpetki i zima, cała para jest do wyrzucenia.
OK, ma to sens, ale trzeba to sprawdzić ;-)
W tym celu napisałem sobie 2 proste programiki w JavaScript [takie, które wykona Windows Script Host].
W obu przyjąłem, że szansa na awarię skarpetki wynosi 5% na włożenie [czyli średnio skarpetka potarga się raz na 20 noszeń], przyjąłem też dla uproszczenia, że nigdy 2 skarpetki się wspólnie nie potargają. Dodatkowo skarpetki nie mają pamięci więc każda w dowolnym noszeniu zachowuje się tak samo i skarpetka noszona pierwszy raz ma dokładnie takie samo prawdopodobieństwo przeżycia jak skarpetka noszona już 100 razy [to założenie stąd, że dzięki temu kod jest o wiele prostszy ;-) a i odpowiada to rzeczywistości bo głównym psujem skarpetek są paznokcie, które zwykle od razu załatwiają skarpetkę ;-)].
No i okazuje się, że po uruchomieniu obu programów przy założeniu, że mamy 10 par skarpetek (a każdy program "zdzierał" te skarpetki 100 tysięcy razy), w sytuacji gdy każda para jest inna skarpetki wystarczą nam na około 200 noszeń, w przypadku gdy wszystkie 10 par jest identycznych mamy tych noszeń około 380 :-)
Przy 5 parach mamy odpowiednio średnio 100 noszeń dla różnych par i 180 dla identycznych.
Czyli dla n różnych par skarpetek przy prawdopodobieństwie potargania równym P mamy :
N = n/P [noszeń]
Dla n identycznych par, przy prawdopodobieństwie potargania równym P mamy zaś noszeń tyle:
N = (n*2-1)/P [noszeń]
Widzimy więc, że kupowanie identycznych par skarpetek pozwala nam na noszenie ich przez czas o prawie 2 razy dłuższy ;-)
A tutaj programy, które pozwolą zweryfikować tego lifehacka ;-)
allDifferent.js [czyli każda para z innej parafii ;-)]:
var DEFECT_PROB = 0.05;
var REPETITIONS = 100000;
var HOW_MANY_PAIRS = 5;

function wasDefectDuringWearing() {
var f = Math.random();
if (f>DEFECT_PROB) return true;
return false;
}

var sum=0;
for (var j=0; j<REPETITIONS ; j++) {
var count = 0;
for (var i=0; i<HOW_MANY_PAIRS; i++) {
do {
count++;
} while (wasDefectDuringWearing());
}
sum+=count;
}
WScript.Echo("--------");
WScript.Echo(sum/REPETITIONS );
allTheSame.js [czyli wszystkie skarpetki takie same ;-)]:
var DEFECT_PROB = 0.05;
var REPETITIONS = 100000;
var HOW_MANY_PAIRS = 10;

function wasDefectDuringWearing() {
var f = Math.random();
if (f>DEFECT_PROB) return true;
return false;
}

var sum = 0;
for (var j=0; j<REPETITIONS ; j++) {
var count = 0;
var socksCount = 2*HOW_MANY_PAIRS;
do {
do {
count++;
} while (wasDefectDuringWearing());
socksCount--;
} while (socksCount>=2)
sum+=count;
}

WScript.Echo("------------");
WScript.Echo(sum/REPETITIONS);
Na koniec ciekawostka, oczywiście gdy pisałem te programiki wyżej to ich nazwy były dokładnie odwrotne do ich działania, bo mi się pomyliło który edytor co zawiera ;-)
A wszystko wyżej powstało jako wynik frustracji po tym, że przez poprzedni tydzień napisałem sobie 2 w miarę fajne rzeczy [Buzz Troll Remover'a i cieniowanie Gourauda w JavaScript] przez co się nakręciłem i fajnie było, po czym przez kolejne dni nic mi do głowy fajnego nie przychodziło i oglądałem głównie TV co jest złe bo smutno jak się nic nie stworzy :-(.


Podobne postybeta
Skarpetki zamiast kapci ;-)
Najprostszy OCR ;-)
Nie jest dobrze ;-)
Manipulowanie statystyką
Tworzenie poprawnych nazw plików :-)

piątek, maja 07, 2010

Go dla Windows przyśpiesza :-)

No i jest nowa wersja Go dla Windows, tym razem kompilacja odbywa się już nie dla mingw, a dla Windows.Dlatego teraz zestaw zmiennych środowiskowych musi wyglądać ciut inaczej niż wyglądał wcześniej [przy założeniu, że go jest w katalogu c:\go]:
GOARCH=386GOBIN=c:\go\binGOOS=windowsGOROOT=c:\go
No i kod wynikowy jest już szybszy o jakieś 2.5 raza niż jeszcze kilka dni temu :-) Nie dostrzegłem jednak wśród pakietów niczego co sugerowałoby możliwość używania jakiegokolwiek GUI w programach w Go.To tyle :-)


Podobne postybeta
Język Go dla Windows :-)
W niewoli numerów wersji...
Raspberry Pi to nie jest demon prędkości ;-)
Dart - to działa i ma sens :-)
Żonglowanie to kolejna sztuczka w zasobniku programisty ;-)

środa, maja 05, 2010

Buzz Troll Remover v0.1.1 :-)

[Update: najnowsza wersja to 0.2.1]Google Buzz jest bardzo miłym produktem, ma jednak jeden malutki problem, choć możemy zablokować niechcianą osobę tak, że nie będzie mogła komentować naszych buzzów to jednak nadal będziemy widzieli komentarze tej osoby pod buzzami od innych osób które obserwujemy.Miałem taki problem ostatnio i postanowiłem zrobić sobie rozszerzenie do Google Chrome, które naprawia tą jedną małą wadę Google Buzz.Rozszerzenie zowie się Buzz Troll Remover [tak, tak wiem, że mam problemy z nazywaniem swoich produktów ;-)] i w chwili obecnej dostępne jest w wersji 0.1.1.W celu instalacji wystarczy w Google Chrome kliknąć na ten link.Zobaczymy takie okienko:Klikamy na Zainstaluj. [rozszerzenie działa w taki sposób, że co 2 sekundy przechodzi przez wszystkie linki na stronie GMAILa w poszukiwaniu takich, które wskazują na komentarze od osób których wolimy unikać, stąd rozszerzenie musi monitorować stronę GMAILa].Po zainstalowaniu do naszych ikon dołączy ikonka ze znakiem ostrzeżenia o trollach ;-) [widoczna najbardziej z prawej]:Po kliknięciu na ikonkę ujrzymy konfigurację rozszerzenia:Gdy chcemy kogoś unikać to w GMAILu w zakładce Buzzowej znajdujemy jakiś komentarz od tej osoby, klikamy na nim prawym myszem i wybieramy z menu "Kopiuj adres linku":Wklejamy ten link do okienka z poprzedniego rysunku, klikamy na "Save Trolls list" i od teraz wszystkie posty osoby, której chcemy unikać wyglądają tak:Jeżeli chcesz skasować daną osobę z listy trolli to musisz usunąć link wskazujący tą osobę z listy w okienku konfiguracji, nacisnąć znów "Save Trolls list" i przeładować stronę GMAILa.Jestem otwarty na komentarze ;-) i wyrazy uznania ;-)


Podobne postybeta
Historia jednego #....
Buzz Troll Remover v0.3.2 zawędrował do galerii rozszerzeń Chrome ;-)
Ewolucja Buzz Troll Remover'a ;-) - czyli nad czym teraz pracuję
Buzz Troll Remover v0.3 - potęga guzików
Gadające Gadu-Gadu

Doda jak George Bernard Shaw i Thomas Jefferson ;-)

Dodę chcą posadzić za stwierdzenie "Wierzę w to, co nam przyniosła matka Ziemia i co odkryto podczas wykopalisk. Są na to dowody i Ciężko wierzyć w coś, co spisał jakiś napruty winem i palący jakieś zioła".To co powiedzą o George'u Bernardzie Shaw, który powiedział o takiej Apokalipsie św. Jana "a peculiar record of the visions of a drug addict". Taki Thomas Jefferson napisał o tej samej Apokalipsie św. Jana "merely the ravings of a maniac, no more worthy nor capable of explanation than the incoherences of our own nightly dreams".Wychodzi na to, że mają szczęście, że już nie żyją, bo inaczej dopadałaby ich nasza dzielna prokuratura ;-)


Podobne postybeta
Nexus 7 wymiata
Ciekawy artykuł
ShiftHappens - ciekawa prezentacja
Dziwne prawo ;-)
In vitro

wtorek, maja 04, 2010

Język Go dla Windows :-)

No i jest już port języka Go dla Windows :-)
Jest już jakiś czas, ale wcześniej go jakoś kilkukrotnie przeoczyłem.
Sportowano jak na razie tylko wersję 32 bitową, czyli narzędzia 8g i 8l [oraz parę innych, których się zwykle z linii poleceń nie używa ;-) albo w dostępnej "paczce" jest tylko 32 bitowa wersja, aż tak daleko nie czytałem].
Tutaj krótka instrukcja pracy z Go na Windows [stworzona na podstawie filmu "szkoleniowego", ale w końcu każdy kto chciałby używać Go na Windows wie jak stworzyć zmienne środowiskowe :-)].
  1. idziemy na stronę do pobierania portu Go dla Windows i pobieramy najnowszy plik
  2. kopiujemy katalog go z archiwum w miejsce gdzie byśmy go chcieli mieć, np. do c:\go [u mnie d:\Software\go ;-)] [czyli plik 8g powinien być pod ścieżką c:\go\bin\8g.exe]
  3. tworzymy 4 zmienne środowiskowe:
    GOARCH=386GOBIN=c:\go\binGOOS=mingwGOROOT=c:\go
  4. modyfikujemy zmienną środowiskową PATH i dodajemy na jej końcu %GOBIN% [oczywiście po średniku ;-)]
No i tada! mamy Go zainstalowane :-) [tak btw. ilu ludzi wie skąd się wzięło "tada!"? ;-)]
Teraz przydałby się jakiś program, np. Hello World, czyli tworzymy plik HelloWorld.go takiej treści:
package main

import "fmt"

func main() {
fmt.Print("Hello World!!!");
}
[tu ostrzeżenie, kompilator dla Windows lubi gdy ostatnia linia programu jest pusta, inaczej wyrzuca błąd]
Po tym kompilujemy program:

8g HelloWorld.go

kompilator stworzył nam plik HelloWorld.8, który musimy zlinkować przy pomocy komendy:

8l -o HelloWorld.exe HelloWorld.8

I teraz już wystarczy uruchomić program wynikowy HelloWorld.exe.
Programy jak na razie szybkością nie porażają ;-) Dla przykładu mój ulubiony program do testowania "szybkości" języków programowania, czyli powtarzane tu już do znudzenia całkowanie numeryczne funkcji e-x2 od -10 do 10 w 10000 kroków, wymaga na moim laptopie mniej więcej 7-8 ms na jedną iterację [czyli jeśli dobrze pamiętam jakieś 10 razy więcej niż wersja w C czy C++ skompilowana w Visual Studio].
Tutaj program:
package main
import "fmt"
import "math"
import "time"

func calc() float {
var sum float=0.0;
var start=0.0;
var stop=10000.0;
var d float=20.0/stop;
for i:=start; i<stop; i++ {
var x float=d*i-10.0;
sum=float(sum+float(math.Exp(float64(-x*x)))*(20.0/stop));
}
return sum;
}

func test() {
start:=time.Nanoseconds();
for i:=0; i<1000; i++ {
calc();
}
stop:=time.Nanoseconds();
var time = float64(stop-start)/1000/1000;
fmt.Printf("%f\n",float64((time)/1000));
}

func main() {
test();
}
Wyniki wyglądały przed chwilą tak:
8.473252
7.443193
6.397191
7.565200
6.411192
7.491195
6.493197
7.519197
Programy wynikowe do małych nie należą ;-) mają w przypadku obu tu przytoczonych blisko 700KB.
Jak na razie nie jestem entuzjastą Go, ale fakt, że do jego używania nie potrzebuję już uruchamiać VMWare Playera dużo ułatwia i może się mu trochę poprzyglądam.


Podobne postybeta
Go wolniejsze od C i JavaScript, i ciut szybsze niż Java ;-) [a jednak od Java'y też wolniejsze]
Raspberry Pi to nie jest demon prędkości ;-)
C# miewa swoje plusy ;-)
Go dla Java'owca ;-) odcinek 1 "klasy"
Wysyłamy pliki do Google Docs przy pomocy Go :-)

niedziela, maja 02, 2010

Cieniowanie Gourauda w JavaScript part 2 - przyśpieszamy :-)

[Update podmieniłem demko, obecne działa na Chrome z prędkością od 90 do 100-110 klatek na sekundę :-)]Byłem zachwycony wynikiem z dzisiejszej nocy czyli 4-5 klatkami na sekundę, ale właśnie przed chwilą przyśpieszyłem do 30-40 klatek na sekundę :-) na co dowód na filmie :-) [tak naprawdę rzeczywista prędkość to około 50 klatek na sekundę, ale w trakcie nagrywania spadła do tych 30-40 klatek]
Wcześniej nie znając zbytnio obiektu Canvas z HTML5 używałem metody fillRect(int,int,int,int), która rysowała prostokąt o zadanych wymiarach w zadanej lokalizacji. Chwila profilowania tego kodu w Chrome pokazała, że to rysowanie oraz ustawianie koloru zabierają najwięcej czasu z całego procesu rysowania.Teraz zamiast rysować przy pomocy prymitywów tworzę obrazki jako pixele tak jak to logika nakazuje ;-)Udało mi się nawet obecną wersję uruchomić na moim G1 gdzie prędkość renderowania to około 0.5 klatki na sekundę :-)
Ze złych informacji, tym razem Opera 10.50 w ogóle zrezygnowała choć nie chciała powiedzieć co jej się nie podoba.Tutaj możecie zobaczyć jak szybko to działa u was :-) [u mnie na Chrome jest to zwykle około 50 klatek na sekundę, na Firefoksie 20-25 klatek na sekundę]
Dla tych co z RSSa/Buzza tutaj link bezpośredni do demka :-)Nadal jestem otwarty na głosy zachwytu ;-)


Podobne postybeta
Cieniowanie Gourauda w JavaScript :-)
Chrome, Firefox, IE9 preview i cieniowanie Gouraud'em w JavaScript
Nie taka Java wolna jak ją opisują...
HD
Lubię enumy

Cieniowanie Gourauda w JavaScript :-)

[Update: parę godzin po tym poście udało mi się wszystko znacznie przyśpieszyć o czym można przeczytać w poście Cieniowanie Gourada w Java Script part 2 - przyśpieszamy :-), tutaj prędkości są od 5 do 10 razy wyższe :-)]Ciekaw byłem czy mi się to uda :-) i udało się :-)Na filmie poniżej można zobaczyć wyniki mojej próby przepisania cieniowania Gourada na JavaScript :-)
Jak widać wynik nie poraża prędkością ;-) 5, w porywach 6 klatek na sekundę na moim laptopie (procesor 2.2 GHz, 2 rdzeniowy, ale tutaj tylko 1 rdzeń jest używany) w Chrome 5.0.375.28 dev, w Firefoksie 1-1.5 klatki na sekundę. W Operze 10.50 wyniki są czasowo podobne do Chrome, ale jak to w Operze coś nie działa tak jak powinno, bo momentami twarz z animacji przypomina kosmitę, innym znów razem kolory się psują.Wszystko działa w oparciu o obiekt Canvas, a wszelkie obliczenia są dokonywane w JavaScript, nie używam tutaj żadnych przyspieszaczy w stylu WebGL.Jeżeli ktoś chciałby sprawdzić jak to działa u niego to wystarczy kliknąć Start Animation :-) Ale uwaga, jeżeli masz słaby komputer to może się okazać, że przeglądarka popadnie w katatonię.
[tutaj to samo, ale ciut większe [2 razy, z tym, że nie liczy się nic więcej, po prostu "pixele" mają rozmiary nie 1x1 a 2x2 :-)]]Sam kod w JavaScript powstał przez "przeportowanie" kodu z Java'y, który to kod w Java'ie powstał z przeprotowania kodu z C :-) [tutaj można zleźć applet w Java'ie który robi to samo co ten JavaScript].Całe portowanie zajęło mi łącznie z 4-6 godzin, może mniej, ale samą zabawę zacząłem tak gdzieś w połowie stycznia 2010, ale po dojściu gdzieś do 30-40% całej pracy zarzuciłem prace, by wrócić do nich dziś w nocy :-)Jak widać JavaScript powoli acz skutecznie staje się pełnoprawnym językiem programowania, choć trochę przeraża, że za jakiś czas może się okazać, że będziemy łączyć się z siecią by pobrać program w JavaScript, który będzie najpierw musiał się skompilować dla naszego procesora i dopiero wtedy nasz procesor będzie go wykonywać ;-)Jestem otwarty na głosy zachwytu ;-)


Podobne postybeta
Cieniowanie Gourauda w JavaScript part 2 - przyśpieszamy :-)
Nie taka Java wolna jak ją opisują...
Chrome, Firefox, IE9 preview i cieniowanie Gouraud'em w JavaScript
Android - nawet platofrma potrafi przeciwko Tobie knuć ;-)
WebGL - dalsze zabawy