<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>guzik &#187; Programowanie</title>
	<atom:link href="http://guzik.net.pl/blog/category/tech/programowanie/feed/" rel="self" type="application/rss+xml" />
	<link>http://guzik.net.pl/blog</link>
	<description>Mój blog</description>
	<lastBuildDate>Fri, 10 Feb 2012 23:44:34 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Gnatt &#8211; czary z mleka</title>
		<link>http://guzik.net.pl/blog/2012/02/gnatt-czary-z-mleka/</link>
		<comments>http://guzik.net.pl/blog/2012/02/gnatt-czary-z-mleka/#comments</comments>
		<pubDate>Fri, 10 Feb 2012 23:44:34 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[diagram Gantta]]></category>
		<category><![CDATA[Gantt]]></category>
		<category><![CDATA[Gnatt]]></category>
		<category><![CDATA[Visual C++]]></category>
		<category><![CDATA[wykres Gantta]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=3693</guid>
		<description><![CDATA[Odkąd pamiętam, przygotowując jakieś raporty, zawsze borykałem się z problemem wizualizacji wzajemnego oddziaływania trwających procesów, np. wpływ odbudowy grupy RAID na czas trwania kopii danych. Wiadomo, że przedstawienie danych tekstowych na wiele się nie zdaje, zwłaszcza jak trwających zadań jest wiele i powtarzają się w raportowanych okresie. Dobrym wyborem jest przedstawienie czasu trwania zadań na [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://guzik.net.pl/blog/wp-content/uploads/2012/02/output.png"><img src="http://guzik.net.pl/blog/wp-content/uploads/2012/02/output-150x80.png" alt="" title="output" width="150" height="80" class="alignright size-thumbnail wp-image-3694" /></a>Odkąd pamiętam, przygotowując jakieś raporty, zawsze borykałem się z problemem wizualizacji wzajemnego oddziaływania trwających procesów, np. wpływ odbudowy grupy RAID na czas trwania kopii danych.<br />
Wiadomo, że przedstawienie danych tekstowych na wiele się nie zdaje, zwłaszcza jak trwających zadań jest wiele i powtarzają się w raportowanych okresie.<br />
Dobrym wyborem jest przedstawienie czasu trwania zadań na diagramie Gantta. <span id="more-3693"></span>Pracowałem z kilkoma programami, ale żaden nie był na tyle wygodny, żebym przy nim pozostał i go mógł polecić do rysowania dowolnego wykresu. Głównie brakowało mi możliwości swobodnego ustawienia rozdzielczości. Ja operuję na minutach, a np. GanttProject na dniach. Chyba w Visio można było ustawić godziny jako jednostki, ale też nie wychodziło to dobrze.</p>
<p>I tak dziś postanowiłem napisać własny program, który naszkicuje wykres na podstawie danych wejściowych. W jakieś 2 godziny miałem działające rozwiązanie, głównie dzięki pomocy mojego potomstwa wchodzącego mi na głowę ;-) Kolejne dwie godziny poświęciłem na kosmetykę i już projekt jest gotowy do udostępnienia.<br />
Co dokładnie robi? Ano, na podstawie dostarczonych danych (plik CSV, format poniżej) generuje grafikę z wykresem. Całość nie wygląda może ładnie (nie ma wstążki :>), ale popracuję jeszcze nad tym.</p>
<p>Plik wsadowy z danymi powinien wyglądać tak (poszczególne pola separowane średnikiem):</p>
<ul>
<li>pierwsza linia: nazwa wykresu (nie używana); początek okresu; koniec okresu,</li>
<li>druga i kolejne linie to zdarzenia: nazwa#kolor (#kolor opcjonalnie &#8211; RRGGBB); początek zadania(; koniec zadania; początek zadania; koniec zadania; &#8230;).</li>
</ul>
<p>Jeśli zadanie wykonywane jest wielokrotnie (np. kopia przyrostowa), to czasy rozpoczęcia i zakończenia wpisujemy w jednej linii. Jeśli zadanie nie skończyło się w danym okresie lub nie podamy czasu zakończenia, odpowiedni słupek będzie dociągnięty do końca wykresu.</p>
<p>Czas podajemy jako liczba sekund od 1 stycznia 1970 r.</p>
<p><a href='http://guzik.net.pl/blog/wp-content/uploads/2012/02/zadania.csv'>Przykładowy plik</a> wygląda tak:</p>
<blockquote><p><code>tydzień 6;1328486400;1329091200<br />
Kopia&nbsp;INCR#505050;1328486000;1328496000;1328608800;1328616000;1328704200;1328736200;1328797800;1328815800<br />
Kopia&nbsp;FULL#505050;1328936400;1329197400<br />
Odbudowa&nbsp;RAID#FF0000;1328704200;1328749200<br />
Formatowanie&nbsp;wolumenu&nbsp;BACKUP;1328949800</code></p></blockquote>
<p>Czego nie ma, ale będzie już po weekendzie:</p>
<ul>
<li>zmiana &#8216;rozdzielczości&#8217;, na której brak narzekałem u innych &#8211; obecnie domyślnie jest 300 sekund (od tego zależy wielkość obrazu),</li>
<li>zmiana parametrów wykresu &#8211; np. wysokość linijek</li>
<li>wybór czcionki,</li>
<li>ramka</li>
<li>swobodny format daty (chyba jest coś do konwersji),</li>
<li>informacje z nagłówka (pierwsza linia) na wykresie,</li>
<li>i wszystko to, o co poprosicie ;-)</li>
</ul>
<p>W najbliższym czasie przygotuję zestawy skryptów do zasilania &#8211; np. zadania RMAN (Oracle), dbms_scheduler (Oracle) czy praca Bacula (<a href="http://guzik.net.pl/blog/2011/06/bweb-i-gentoo/">Bweb</a> przestałem już używać, a rysowałem w nim tylko takie wykresy).<br />
Jeśli macie jakieś pomysły na wykorzystanie, dajcie znać.</p>
<p>I najważniejsze &#8211; <a href="http://infowizja.nazwa.pl/projects/Gnatt/publish.htm">strona projektu</a>. Dwa dni temu poznałem <em>Publish</em> w Visual C#, więc teraz aktualizacje będą lepiej dystrybuowane :-)</p>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2012/02/gnatt-czary-z-mleka/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>O (Net-)SNMP jeszcze trochę</title>
		<link>http://guzik.net.pl/blog/2011/12/o-net-snmp-jeszcze-troche/</link>
		<comments>http://guzik.net.pl/blog/2011/12/o-net-snmp-jeszcze-troche/#comments</comments>
		<pubDate>Sun, 18 Dec 2011 13:36:38 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[SNMP]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=3560</guid>
		<description><![CDATA[O SNMP pisałem już kilka razy. Tym razem notka o rozszerzeniu możliwości serwera (Net-SNMP) i prezentacji danych we własnych OID&#8217;ach. Najprościej wykonać to można dodając do konfiguracji dyrektywę extend (kiedyś exec lub sh). Składnia wygląda tak: extend [MIBOID] NAME PROG ARGS A na przykładzie: extend .1.3.6.1.4.1.31337 Test /root/scripts/test.sh testarg1 Przy okazji pozdrawiam firmę Union &#038; [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://guzik.net.pl/blog/tag/snmp/">O SNMP pisałem już kilka razy</a>. Tym razem notka o rozszerzeniu możliwości serwera (Net-SNMP) i prezentacji danych we własnych OID&#8217;ach.</p>
<p>Najprościej wykonać to można dodając do konfiguracji dyrektywę <code>extend</code> (kiedyś <code>exec</code> lub <code>sh</code>). Składnia wygląda tak:</p>
<blockquote><p><code>extend [MIBOID] NAME PROG ARGS</code></p></blockquote>
<p>A na przykładzie:</p>
<blockquote><p><code>extend .1.3.6.1.4.1.31337 Test /root/scripts/test.sh testarg1</code></p></blockquote>
<p>Przy okazji pozdrawiam firmę Union &#038; Comstar, której PEN (<em>Private Enterprise Number</em>) pożyczyłem :-) <span id="more-3560"></span><br />
Wadą tego rozwiązania jest fakt, że każdy wynik zwracany przez zewnętrzny program (<code>printf</code> czy <code>echo</code>) traktowany jest jak <code>STRING</code>. Gdy chcemy uzyskać <code>INTEGER</code> możemy wprawdzie posłużyć się kodem wyjścia, ale mamy do dyspozycji zakres 0-255. Do pomiaru temperatury w serwerowni czy na procesorze się może przyda, ale do sprawdzenia pamięci wykorzystywanej przez dany proces już niekoniecznie.</p>
<p>Net-SNMP umożliwia nam wykorzystanie Perl&#8217;a &#8211; a konkretnie modułu NetSNMP::agent, do tworzenia własnych wtyczek (chyba dla Python też jest wsparcie).<br />
Jako że kiepski ze mnie programista, a w szczególności programista Perl, postaram się wspierać swój przekaz kodem. I tak stworzenie agenta możemy wykonać następująco:</p>
<blockquote><p><code>use NetSNMP::agent;</p>
<p>my $agent = new NetSNMP::agent();</code></p></blockquote>
<p>Następnie tworzymy funkcję i rejestrujemy ją, by użyć przy wywołaniu konkretnego OID&#8217;a:</p>
<blockquote><p><code>sub callback_function {<br />
&nbsp;&nbsp;my ($handler, $registration_info, $request_info, $requests) = @_;<br />
&nbsp;&nbsp;my $request;<br />
&nbsp;&nbsp;for($request = $requests; $request; $request = $request->next()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;my $oid = $request->getOID();<br />
&nbsp;&nbsp;&nbsp;&nbsp;if ($oid == new NetSNMP::OID(".1.3.6.1.4.1.31337.1.1.0")) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$request->setValue(ASN_INTEGER, hex(substr $valstring, 4, 2)-40);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}</p>
<p>$agent->register("callback function", ".1.3.6.1.4.1.31337.1", \&#038;callback_function);</code></p></blockquote>
<p>Funkcja jest wywoływana z czteroma parametrami: <code>HANDLER</code>, <code>REGISTRATION_INFO</code>, <code>REQUEST_INFO</code>, i <code>REQUESTS</code>. <code>REQUEST_INFO</code> może zawierać dwa tryby &#8211; <code>MODE_GET</code> i <code>MODE_GETNEXT</code>. Oczywiście przy jednokrotnym sprawdzaniu OID&#8217;a (np. przez Cacti) nie ma to znaczenia, ale gdybyśmy chcieli sprawdzić całe drzewo używając np. <code>snmpwalk</code>, to przy <code>MODE_GETNEXT</code> musimy podać adres kolejnego OID&#8217;a, który ma być sprawdzony po bieżącym. W przeciwnym razie <code>snmpwalk</code> skończy odczyt.</p>
<blockquote><p><code>$request->setOID(".1.3.6.1.4.1.31337.1.1.1");</code></p></blockquote>
<p>W odpowiedzi agent może zwrócić jeden spośród dwudziestu typów danych. Ja używam jedynie <code>ASN_INTEGER</code> i <code>ASN_OCTET_STR</code>. Resztę można znaleźć w dokumentacji.</p>
<p>Po stworzeniu modułu dodajemy jego wywołanie do Net-SNMP w pliku <code>snmpd.conf</code>:</p>
<blockquote><p><code>perl do "/root/scripts/test.pl"</code></p></blockquote>
<p>Następnie restartujemy demona i możemy odczytywać nasze dane. Należy pamiętać, że po każdej zmianie wtyczki niezbędne jest ponowne przeładowanie.</p>
<p>Czytaj też:</p>
<ul>
<li><a href="http://www.net-snmp.org/wiki/index.php/Tut:Extending_snmpd_using_perl">Extending snmpd using perl</a></li>
<li><a href="http://docs.redhat.com/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/sect-System_Monitoring_Tools-Net-SNMP-Extending.html">RedHat Documentation: Extending Net-SNMP</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2011/12/o-net-snmp-jeszcze-troche/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Zmiany w libwww-perl</title>
		<link>http://guzik.net.pl/blog/2011/11/zmiany-w-libwww-perl/</link>
		<comments>http://guzik.net.pl/blog/2011/11/zmiany-w-libwww-perl/#comments</comments>
		<pubDate>Fri, 18 Nov 2011 22:03:15 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[libwww-perl]]></category>
		<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=3466</guid>
		<description><![CDATA[Jakiś czas temu (dokładnie to 27 marca) z biblioteki libwww-perl wydzielony został moduł LWP::Protocol::https. Jak można przeczytać w dokumentacji od wersji 6.01 biblioteki nie zaszły żadne zmiany w kodzie tego modułu. W zeszłym tygodniu moduł został oznaczony jako stabilny w paczkach dla Gentoo (dev-perl/LWP-Protocol-https). Możliwa się stała jego aktualizacja i tym samym libwww-perl (dev-perl/libwww-perl). No [...]]]></description>
			<content:encoded><![CDATA[<p>Jakiś czas temu (dokładnie to 27 marca) z biblioteki <a href="http://search.cpan.org/~gaas/libwww-perl-6.03/">libwww-perl</a> wydzielony został moduł <a href="http://search.cpan.org/~gaas/LWP-Protocol-https-6.02/">LWP::Protocol::https</a>. Jak można przeczytać w dokumentacji od wersji 6.01 biblioteki nie zaszły żadne zmiany w kodzie tego modułu.<br />
W zeszłym tygodniu moduł został oznaczony jako stabilny w paczkach dla Gentoo (<a href="http://packages.gentoo.org/package/dev-perl/LWP-Protocol-https">dev-perl/LWP-Protocol-https</a>). Możliwa się stała jego aktualizacja i tym samym libwww-perl (<a href="http://packages.gentoo.org/package/dev-perl/libwww-perl">dev-perl/libwww-perl</a>). No i zaktualizowałem. I jednak coś się zmieniło.</p>
<p>SOAP::Lite, który korzysta z libwww-perl nagle zaczął zgłaszać błąd certyfikatu serwera (tzw. <em>self-signed</em>), z którego wywoływał żądanie:</p>
<blockquote><p><code>500 Can't connect to server:443 (certificate verify failed) at <strong>/usr/lib/nagios/plugins/sms.pl</strong> line 7<br />
</code></p></blockquote>
<p><span id="more-3466"></span><br />
Rozwiązanie problemu jest trywialne, weryfikację certyfikatu można wyłączyć ustawiając odpowiednią zmienną:</p>
<blockquote><p><code>$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}=0;</code></p></blockquote>
<p>lub stosowną opcję (klasa <a href="http://search.cpan.org/~gaas/libwww-perl-6.03/lib/LWP/UserAgent.pm">LWP::UserAgent</a>):</p>
<blockquote><p><code>LWP::UserAgent->new(ssl_opts => { verify_hostname => 0 });</code></p></blockquote>
<p>I znów działa jak dawniej.</p>
<p>W wersji 5.837 i wcześniejszych biblioteki libwww-perl sprawdzanie było wyłączone. Ja aktualizowałem z 5.836.</p>
<p>Wnikliwy czytelnik zauważył pewnie nazwę wywoływanego skryptu. Jak można się domyśleć ma on strategiczne znaczenie. Eh&#8230;</p>
<p>Swoją drogą przy okazji zwróciłem uwagę na nazewnictwo, a właściwie numerację paczek w Gentoo. Otóż libwww-perl w wersji 6.03 nazywa się dev-perl/libwww-perl-6.30.0, z kolei moduł LWP::Protocol::https 6.02 to dev-perl/LWP-Protocol-https-6.20.0. Ktoś potrafi to wyjaśnić? W ebuild&#8217;zie w zmiennej <code>MODULE_VERSION</code> jest właściwa wersja.</p>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2011/11/zmiany-w-libwww-perl/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dzień Programisty</title>
		<link>http://guzik.net.pl/blog/2011/09/dzien-programisty/</link>
		<comments>http://guzik.net.pl/blog/2011/09/dzien-programisty/#comments</comments>
		<pubDate>Tue, 13 Sep 2011 00:56:46 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[Programowanie]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=2150</guid>
		<description><![CDATA[W zeszłym roku chciałem coś napisać z okazji Dnia Programisty, ale skończyłem na tych dwóch odnośnikach (poniżej). W zasadzie nie opublikowałem tego, bo jakoś nie było czasu, ale zaśmieca mi Kokpit w WordPress (leży tez wpis z wakacji &#8217;08), więc puszczę jak jest. W sumie to chyba aktualne i dziś. Maciej Zbrzezny: Jak uczyć się [...]]]></description>
			<content:encoded><![CDATA[<p>W zeszłym roku chciałem coś napisać z okazji Dnia Programisty, ale skończyłem na tych dwóch odnośnikach (poniżej). W zasadzie nie opublikowałem tego, bo jakoś nie było czasu, ale zaśmieca mi Kokpit w WordPress (leży tez wpis z wakacji &#8217;08), więc puszczę jak jest. W sumie to chyba aktualne i dziś.</p>
<ul>
<li><a href="http://maciej-progtech.blogspot.com/2010/04/jak-uczyc-sie-c-pl.html">Maciej Zbrzezny: Jak uczyć się C#? [PL]</a></li>
<li><a rel="bookmark" href="http://blog.matthew.org.pl/2010/02/10/jakiego-jezyka-programowania-sie-nauczyc/">Matthew: Jakiego języka programowania się nauczyć?</a></li>
</ul>
<p>Jeśli ktoś pyta skąd i po co, to odpowiedź poniżej (na nic bardziej kreatywnego mnie teraz nie stać):</p>
<blockquote><p><code>mysql> SELECT DAYOFYEAR(CURDATE());<br />
+----------------------+<br />
| DAYOFYEAR(CURDATE()) |<br />
+----------------------+<br />
|                  256 |<br />
+----------------------+<br />
1 row in set (0.09 sec)</code></p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2011/09/dzien-programisty/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Dodanie czasu w GPS Track</title>
		<link>http://guzik.net.pl/blog/2011/08/dodanie-czasu-w-gps-track/</link>
		<comments>http://guzik.net.pl/blog/2011/08/dodanie-czasu-w-gps-track/#comments</comments>
		<pubDate>Tue, 02 Aug 2011 23:07:50 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[GPS Track]]></category>
		<category><![CDATA[Visual C++]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=3173</guid>
		<description><![CDATA[W czerwcu w trakcie testowania aplikacji do śledzenia tras (via GPS) wspominałem o programie GPS Track. Aplikacja jest wystarczająca do zapisu samej ścieżki, ale niestety nie zapisuje znaczników czasu dla każdego punktu, więc jest bezużyteczna w przypadku korzystania z serwisu Endomondo (nie sprawdzałem jak zachowuje się Sports Tracker). Nie zapisuje też wysokości, tym samym tracimy [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.qcontinuum.org/gpstrack/"><img alt="" src="http://www.qcontinuum.org/gpstrack/gpstrack.gif" class="alignright" width="240" height="246" /></a>W czerwcu w trakcie testowania aplikacji do śledzenia tras (via GPS) wspominałem o programie <a href="http://www.qcontinuum.org/gpstrack/">GPS Track</a>. Aplikacja jest wystarczająca do zapisu samej ścieżki, ale niestety nie zapisuje znaczników czasu dla każdego punktu, więc jest bezużyteczna w przypadku korzystania z serwisu <a href="http://www.endomondo.com/">Endomondo</a> (nie sprawdzałem jak zachowuje się <a href="http://www.sports-tracker.com/">Sports Tracker</a>). Nie zapisuje też wysokości, tym samym tracimy rozszerzone informacje o treningu (Endomondo czy Google Earth sam sobie tego nie &#8216;dopisuje&#8217;).<span id="more-3173"></span></p>
<p>Możemy jednakże dodać odpowiednie atrybuty samemu i dostosować plik do wymagań Endomondo. Ja zrobiłem to tak:</p>
<pre>OpenFileDialog fDialog = new OpenFileDialog();
fDialog.Title = "Open GPX 1.0 File";
fDialog.Filter = "GPX Files|*.gpx";
if (fDialog.ShowDialog() == DialogResult.OK) {
    Chilkat.Xml xml = new Chilkat.Xml();
    xml.LoadXmlFile(fDialog.FileName.ToString());
    Chilkat.Xml root = xml.FirstChild();
    Chilkat.Xml seg = root.FindChild("trkseg");
    Chilkat.Xml pt = seg.FirstChild();
    DateTime pttime = DateTime.Parse(root.GetChildContent("name"));
    string oPath = Path.GetDirectoryName(fDialog.FileName) + "\\" + pttime.ToString("yyyyMMdd-HHmmss") + ".gpx";
    while (pt != null) {
        pt.NewChild("time", pttime.ToString("s"));
        pttime = pttime.AddSeconds(2);
//      listBox1.Items.Add(pt.GetAttrValue("lat"));
//      listBox1.Items.Add(pttime.ToString("s"));
        pt = pt.NextSibling();
    }
    xml.SaveXml(oPath);
}
</pre>
<p>Słowem komentarza:</p>
<ul>
<li>kompilowane w <a href="http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-csharp-express">Visual C# 2010</a> + <a href="http://chilkatsoft.com/xml-dotnet.asp">Chilkat XML .NET</a>,</li>
<li>czas w formacie <a href="http://pl.wikipedia.org/wiki/ISO_8601">ISO 8601</a> czy jak kto woli &#8211; <a href="http://msdn.microsoft.com/en-us/library/az4se3k1%28v=VS.100%29.aspx#Sortable"><em>sortable</em></a> (linia 12 i 15),</li>
<li>GPS Track po eksporcie ścieżki do GPX zapisuje w <code>name</code> czas początku rejestracji, więc można go pobrać do pierwszego punktu (linia 10), a następnie dodawać przesunięcie ustawione w programie (linia 13) &#8211; w moim przypadku 2 sekundy (tego nie ma w XML, więc trzeba to wiedzieć/sprawdzić ustawienie).</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2011/08/dodanie-czasu-w-gps-track/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHPExcel</title>
		<link>http://guzik.net.pl/blog/2011/03/phpexcel/</link>
		<comments>http://guzik.net.pl/blog/2011/03/phpexcel/#comments</comments>
		<pubDate>Wed, 16 Mar 2011 18:56:01 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Excel]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[PHPExcel]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=2769</guid>
		<description><![CDATA[Czasem spadają na mnie jakieś drobne projekty, którymi wcale nie chcę się zajmować, bo okazuje się, że wymaga to głębszego poznania tematu i zajmuje więcej czasu niż przerwa śniadaniowa. Tym razem dostałem do wypełnienia arkusz kalkulacyjny MS Excel danymi przesłanymi przez klienta. Dostępna technologia &#8211; PHP. Od razu zacząłem szukać gotowca i znalazłem! PHPExcel. Po [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft" src="http://download.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=phpexcel&amp;DownloadId=65397&amp;Build=17672" alt="" width="349" height="80" />Czasem spadają na mnie jakieś drobne projekty, którymi wcale nie chcę się zajmować, bo okazuje się, że wymaga to głębszego poznania tematu i zajmuje więcej czasu niż przerwa śniadaniowa. Tym razem dostałem do wypełnienia arkusz kalkulacyjny MS Excel danymi przesłanymi przez klienta. Dostępna technologia &#8211; PHP.</p>
<p>Od razu zacząłem szukać gotowca i znalazłem! PHPExcel. Po krótkiej pracy z nim wiem, że nie jest to idealne narzędzie, ale może to wynikać z formatu pliku jaki obrabiałem i od tego jak i czym został wcześniej zapisany (wzór dostarczony z zewnątrz). Z dwóch wyglądających podobnie komórek po otwarciu i zapisaniu przez PHPExcel nagle jedna gubi formatowanie. Dziwne. Ale jako, że nie chciałem się zagłębiać, uznałem, że tak właśnie musi być.<br />
Jako, że arkusze nie są skomplikowane, to przed samym zapisem robię &#8216;normalizację&#8217; komórek, czyli ustawiam takie formatowanie, jakie jest w pliku źródłowym i wszystko działa.</p>
<p>Prócz wypełniania komórek odpowiednimi wartościami i zmianie formatowania nic więcej nie robiłem (a pewnie się da). Do takich celów, uważam, że projekt nadaje się wystarczająco.</p>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2011/03/phpexcel/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>flaker</title>
		<link>http://guzik.net.pl/blog/2011/02/flaker/</link>
		<comments>http://guzik.net.pl/blog/2011/02/flaker/#comments</comments>
		<pubDate>Sat, 26 Feb 2011 22:21:03 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[flaker]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=2715</guid>
		<description><![CDATA[W październiku zeszłego roku stworzyłem prostego klienta Blip i twitter w C i Perl. Dziś, w końcu, udało mi się dotrzeć do API flakera (jak pisałem poprzednie programy, to długo tej strony nie było, a dziś jest pod adresem http://blog_backup.flaker.pl/api/index.html). W zasadzie to niewiele trzeba zmienić kod do twitter: nazwa użytkownika to user-&#62;login (linia 20), [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://flaker.pl/"><img class="alignleft size-medium wp-image-2726" title="download" src="http://guzik.net.pl/blog/wp-content/uploads/2011/02/download-300x149.png" alt="" width="300" height="149" /></a>W październiku zeszłego roku stworzyłem prostego klienta <a href="http://guzik.net.pl/blog/2010/10/klient-blip-perl/">Blip</a> i <a href="http://guzik.net.pl/blog/2010/10/klient-twitter-c/">twitter</a> w C i Perl. Dziś, w końcu, udało mi się dotrzeć do <a href="http://blog.flaker.pl/api/">API flakera</a> (jak pisałem poprzednie programy, to długo tej strony nie było, a dziś jest pod adresem <a href="http://blog_backup.flaker.pl/api/index.html">http://<strong>blog_backup</strong>.flaker.pl/api/index.html</a>). W zasadzie to niewiele trzeba zmienić kod do twitter:</p>
<ul>
<li>nazwa użytkownika to <code>user-&gt;login</code> (linia 20),</li>
<li>data i godzina wpisu &#8211; <code>datetime</code> (lub jak kto woli <code>time</code> czy nawet <code>timestamp</code>; linia 21),</li>
<li>no i oczywiście URL: <code>http://api.flaker.pl/api/html:false/tag:tag/limit:limit</code> (linia 63).</li>
</ul>
<p>Pliku różnicowego nie zamieszczam, bo szanuję czytelników ;-)</p>
<p>Nie, nie mam konta w tym serwisie (a w tamtych tylko firmowe).</p>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2011/02/flaker/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Klient twitter (C)</title>
		<link>http://guzik.net.pl/blog/2010/10/klient-twitter-c/</link>
		<comments>http://guzik.net.pl/blog/2010/10/klient-twitter-c/#comments</comments>
		<pubDate>Thu, 14 Oct 2010 14:56:56 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=2241</guid>
		<description><![CDATA[Źródła klienta twitter poniżej. W zasadzie to tylko mała zmiana w stosunku do klienta Blip, bo różnią się formatem danych wejściowych (ale nadal to JSON) i nazwami pól (user_path -&#62; from_user, body -&#62; text). Tak jak wcześniej &#8211; kod nie jest optymalny. Mam tego świadomość, dlatego czekam na wszelkie uwagi. W przypadku korzystania z tego [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://twitter.com/"><img class="alignleft" title="twitter logo" src="http://a2.twimg.com/a/1287010001/images/twitter_logo.png" alt="" width="216" height="56" /></a>Źródła klienta twitter poniżej. W zasadzie to tylko mała zmiana w stosunku do <a href="http://guzik.net.pl/blog/2010/10/klient-blip-c">klienta Blip</a>, bo różnią się formatem danych wejściowych (ale nadal to <a href="http://json.org/">JSON</a>) i nazwami pól (<code>user_path</code> -&gt; <code>from_user</code>, <code>body</code> -&gt; <code>text</code>). Tak jak wcześniej &#8211; kod nie jest optymalny. Mam tego świadomość, dlatego czekam na wszelkie uwagi.<br />
W przypadku korzystania z tego wyszukiwania trzeba wiedzieć, że nie są dostępne wszystkie statusy, a jedynie te najnowsze.<span id="more-2241"></span></p>
<pre>/* Bartłomiej  guzik Syryjczyk
 * 2010-10-11
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;curl/curl.h&gt;
#include &lt;json/json.h&gt;

int fnc(void *ptr, size_t size, size_t nmemb, void *stream) {
    json_object * new_obj;
    json_object * jvalue;

    new_obj = json_tokener_parse(ptr);

    json_object_object_foreach(new_obj, key, val)
        if(json_object_get_type(val) == json_type_array)
            for (int i=0; i&lt;json_object_array_length(val); i++) {
                jvalue = json_object_array_get_idx(val, i);
                printf(&quot;%s\t&quot;, json_object_get_string(json_object_object_get(jvalue, &quot;from_user&quot;)));
                printf(&quot;%s\t&quot;, json_object_get_string(json_object_object_get(jvalue, &quot;created_at&quot;)));
                printf(&quot;%s\n&quot;, json_object_get_string(json_object_object_get(jvalue, &quot;text&quot;)));
            }

    return 0;
}

int main(int argc, char* argv[]) {
    CURL *curl;
    CURLcode res;
    struct curl_slist *slist = NULL;
    char *user = &quot;niebezpiecznik&quot;;
    char url[128];
    int limit = 3, offset = 0, debug = 0;

    for(int i = 1; i &lt; argc; i++) {
        if (argv[i][0] == &#039;-&#039;)
            switch (argv[i][1]) {
                case &#039;u&#039;:
                    user = argv[++i];
                    break;
                case &#039;l&#039;:
                    limit = atoi(argv[++i]);
                    break;
                case &#039;o&#039;:
                    offset = atoi(argv[++i]);
                    break;
                case &#039;v&#039;:
                    debug = 1;
                    break;
            }
    }

    curl = curl_easy_init();
    if(curl) {
        curl_easy_setopt(curl, CURLOPT_VERBOSE, debug);
        curl_easy_setopt(curl, CURLOPT_ENCODING, &quot;UTF-8&quot;);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, &quot;gift-0.2 Infowizja.pl&quot;);
        slist = curl_slist_append(slist, &quot;Accept: application/json&quot;);
        slist = curl_slist_append(slist, &quot;X-Blip-API: 0.02&quot;);
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
        for (int cnt = 1; cnt &lt;= limit; cnt++) {
            sprintf(url, &quot;http://search.twitter.com/search.json?q=from:%s&amp;rpp=1&amp;page=%d&quot;, user, offset+cnt);
            curl_easy_setopt(curl, CURLOPT_URL, url);
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fnc);
            res = curl_easy_perform(curl);
        }
    }
    curl_easy_cleanup(curl);
    return 0;
}</pre>
<p>Pozdrowienia dla ekipy <a href="http://niebezpiecznik.pl/">Niebezpiecznik</a>&#8216;a (vide linia 32 kodu i domyślna wartość <code>*user</code>). Wiem, że są RSS&#8217;y w Blip i Atom w twitter, ale jeszcze nie dotknąłem <a href="http://xmlsoft.org/">libxml2</a>.</p>
<p>Krótkie porównanie API mikroblogów znalazłem tu:</p>
<ul>
<li><a title="Trwały link do Dokumentacje API popularnych mikroblogów, Grona i Delicious" rel="bookmark" href="http://polishwords.com.pl/blog/2009/dokumentacje-api-popularnych-mikroblogow-grona-i-delicious/"><span><span class="naglowek">Dokumentacje API popularnych mikroblogów, Grona i Delicious</span></span></a></li>
</ul>
<p>Zobacz także bardziej zaawansowany projekt Rafała Wileczka (Python):
<ul>
<li><a href="http://tylkooprogramowaniu.blogspot.com/p/projekty.html#blogtweet">BlogTweetProjectGUI 0.0.1</a></li>
</ul>
<p>Inne:</p>
<ul>
<li><a href="http://dev.twitter.com/doc/get/search">GET search | dev.twitter.com</a></li>
<li><a href="http://apiwiki.twitter.com/Twitter-Search-API-Method%3A-search">Twitter Search API Method: search</a></li>
<li><a href="http://joysofprogramming.com/category/cc/json-c/">Joys of Programming: C/C++ -> json-c</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2010/10/klient-twitter-c/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Klient Blip (Perl)</title>
		<link>http://guzik.net.pl/blog/2010/10/klient-blip-perl/</link>
		<comments>http://guzik.net.pl/blog/2010/10/klient-blip-perl/#comments</comments>
		<pubDate>Wed, 13 Oct 2010 20:57:10 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[BLIP]]></category>
		<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=2235</guid>
		<description><![CDATA[Po południu opublikowałem źródła klienta Blip w C, teraz odnalazłem kod w Perl (mniej funkcjonalny) i wklejam poniżej #!/usr/bin/perl -w use strict; use WWW::Mechanize; use JSON -support_by_pp; my $tag = "perl"; my $limit = 3; if (@ARGV) { $tag = shift; } if (@ARGV) { $limit = shift; } my $url = "http://blip.pl/tags/$tag?limit=$limit"; my $browser [...]]]></description>
			<content:encoded><![CDATA[<p>Po południu opublikowałem <a title="http://guzik.net.pl/blog/2010/10/klient-blip-c/" href="http://guzik.net.pl/blog/2010/10/klient-blip-c/">źródła klienta Blip w C</a>, teraz odnalazłem kod w Perl (mniej funkcjonalny) i wklejam poniżej</p>
<pre>#!/usr/bin/perl -w

use strict;
use WWW::Mechanize;
use JSON -support_by_pp;

my $tag = "perl";
my $limit = 3;

if (@ARGV) {
    $tag = shift;
}
if (@ARGV) {
    $limit = shift;
}

my $url = "http://blip.pl/tags/$tag?limit=$limit";
my $browser = WWW::Mechanize->new();
$browser->add_header('Accept' => 'application/json', 'X-Blip-api' => '0.02', 'X-Blip-Application' => 'Infowizja.pl');
$browser->get($url);
my $content = $browser->content();
my $json = new JSON;
my $json_text = $json->decode($content);

eval {
    foreach my $tag(@{$json_text}) {
        $tag->{user_path} =~ s/^.*\///g;
        print "$tag->{created_at}\t$tag->{user_path}\t$tag->{body}\n";
    }
};</pre>
<p>Najlepiej uruchamiać ze zmienną środowiskową <code>PERL_UNICODE=S</code> (na terminalu wyświetlającym znaki w UTF-8).</p>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2010/10/klient-blip-perl/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Klient Blip (C)</title>
		<link>http://guzik.net.pl/blog/2010/10/klient-blip-c/</link>
		<comments>http://guzik.net.pl/blog/2010/10/klient-blip-c/#comments</comments>
		<pubDate>Wed, 13 Oct 2010 13:37:43 +0000</pubDate>
		<dc:creator>guzik</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[BLIP]]></category>
		<category><![CDATA[C]]></category>

		<guid isPermaLink="false">http://guzik.net.pl/blog/?p=2216</guid>
		<description><![CDATA[Wspominałem już, że nie jestem programistą? Dlatego proszę o wszelkie uwagi odnośnie poniższego kodu. Jest to prosty klient Blip, który w zasadzie tylko pobiera statusy konkretnego użytkownika (^user) lub o konkretnym znaczniku (#tag). /* Bartłomiej guzik Syryjczyk * 2010-10-11 */ #include &#60;stdio.h&#62; #include &#60;stdlib.h&#62; #include &#60;curl/curl.h&#62; #include &#60;json/json.h&#62; int fnc(void *ptr, size_t size, size_t nmemb, [...]]]></description>
			<content:encoded><![CDATA[<p><img alt="" src="http://blip.pl/images/logos/blip80.png" title="Blip" class="alignright" width="80" height="51" />Wspominałem już, że <a href="http://guzik.net.pl/blog/2010/08/visual-c/">nie jestem programistą</a>? Dlatego proszę o wszelkie uwagi odnośnie poniższego kodu.<br />
Jest to prosty klient Blip, który w zasadzie tylko pobiera statusy konkretnego użytkownika (<code>^user</code>) lub o konkretnym znaczniku (<code>#tag</code>).<span id="more-2216"></span></p>
<pre>/* Bartłomiej  guzik Syryjczyk
 * 2010-10-11
 */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;curl/curl.h&gt;
#include &lt;json/json.h&gt;

int fnc(void *ptr, size_t size, size_t nmemb, void *stream) {
    json_object * new_obj;
    json_object * jvalue;

    new_obj = json_tokener_parse(ptr);

    if(json_object_get_type(new_obj) == json_type_array)
        for (int i=0; i&lt;json_object_array_length(new_obj); i++) {
            jvalue = json_object_array_get_idx(new_obj, i);
            printf(&quot;%s\t&quot;, json_object_get_string(json_object_object_get(jvalue, &quot;user_path&quot;))+7);
            printf(&quot;%s\t&quot;, json_object_get_string(json_object_object_get(jvalue, &quot;created_at&quot;)));
            printf(&quot;%s\n&quot;, json_object_get_string(json_object_object_get(jvalue, &quot;body&quot;)));
        }
    return 0;
}

int main(int argc, char* argv[]) {
    CURL *curl;
    CURLcode res;
    struct curl_slist *slist = NULL;
    char *tag = &quot;tag&quot;, *user = &quot;&quot;;
    char url[64];
    int limit = 3, offset = 0, debug = 0;

    for(int i = 1; i &lt; argc; i++) {
        if (argv[i][0] == &#039;-&#039;)
            switch (argv[i][1]) {
                case &#039;t&#039;:
                    tag = argv[++i];
                    break;
                case &#039;u&#039;:
                    user = argv[++i];
                    break;
                case &#039;l&#039;:
                    limit = atoi(argv[++i]);
                    break;
                case &#039;o&#039;:
                    offset = atoi(argv[++i]);
                    break;
                case &#039;v&#039;:
                    debug = 1;
                    break;
            }
    }

    curl = curl_easy_init();
    if(curl) {
        curl_easy_setopt(curl, CURLOPT_VERBOSE, debug);
        curl_easy_setopt(curl, CURLOPT_ENCODING, &quot;UTF-8&quot;);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, &quot;gift-0.2 Infowizja.pl&quot;);
        slist = curl_slist_append(slist, &quot;Accept: application/json&quot;);
        slist = curl_slist_append(slist, &quot;X-Blip-API: 0.02&quot;);
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
        for (int cnt = 0; cnt &lt; limit; cnt++) {
            if (strcmp(user, &quot;\0&quot;))
                sprintf(url, &quot;blip.pl/users/%s/statuses?limit=1&amp;offset=%d&quot;, user, offset+cnt);
            else
                sprintf(url, &quot;blip.pl/tags/%s?limit=1&amp;offset=%d&quot;, tag, offset+cnt);
            curl_easy_setopt(curl, CURLOPT_URL, url);
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fnc);
            res = curl_easy_perform(curl);
        }
    }
    curl_easy_cleanup(curl);
    return 0;
}</pre>
<p>Kompilacja:</p>
<blockquote><p><code>gcc -std=c99 -g -O3 -Wall    -c -o blip.o blip.c</code></p></blockquote>
<p>W linii 59 jest nazwa klienta, która nie wiem co oznacza. Bodajże &#8222;t&#8221; oznaczało twitter, bo początkowo miały być obsługiwane <em>tweetnięcia</em> (dorobię wkrótce).</p>
<p>Cały kod jest częścią większego projektu pisanego dla <a href="http://infowizja.pl">Infowizji</a>.</p>
<p>Czujcie się swobodnie przerabiając ten kod, ale dajcie znać, jak coś udoskonalicie. <a href="http://blipapi.wikidot.com/">Blip API</a> jest dość zrozumiałe.</p>
<p>Z <a href="http://oss.metaparadigm.com/json-c/">json-c</a> mam problem. Przekazywanie większych tablic (np. ponad 3 statusy Blip) daje <code>Segmentation fault</code>. Z tego powodu robiona jest sztuczka z limit i offset (pętla zaczyna się w linii 63).<br />
Tak samo problematyczny jest znak &#8222;&gt;&#8221;. Dlatego proszę nie używać uśmieszków jak informujecie przyjaciół o swoich poczynaniach :&gt;</p>
<p>Nie zrozumiałem <code>CURLOPT_WRITEDATA</code>, więc wywołanie programu (z opcją <code>-v</code>) kończy się komunikatem:</p>
<blockquote><p><code>* Failed writing body (0 != 324)<br />
* Closing connection #0<br />
* Failed writing received data to disk/application</code></p></blockquote>
<p>Jeśli ustawiacie dodatkowe nagłówki za pomocą <code>curl_slist_append()</code> (u mnie linie 60-62), pamiętajcie, że <em>append</em> w nazwie funkcji robi <em>append</em>. Ustawienie tego samego nagłówek kilka razy skutkuje odpowiedzią serwera:</p>
<blockquote><p><code>HTTP/1.1 400 Bad Request</code></p></blockquote>
<p>Napisałem też identycznego klienta w Perl. Ale coś się zagubił w repozytorium&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://guzik.net.pl/blog/2010/10/klient-blip-c/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

