RSS
 

Bazaar uzupełnieniem SVN-a

11 cze

Subversion – jeden model pracy

Najbardziej popularnym systemem wersjonowania jest Subversion. Został on zaprojektowany do pracy w sposób scentralizowany. Działa to tak, że gdzieś na serwerze znajduje się centralne repozytorium z którego programista pobiera kopię roboczą na swój lokalny komputer. Dokonuje modyfikacji plików po czym zatwierdza dokonane zmiany w repozytorium centralnym. Taki model pracy ma swoje zalety jednak zdarzają się sytuacje kiedy przydała by się lokalna wersja repozytorium. Poczciwy SVN nie daje jednak możliwości pracy w sposób rozproszony co jest jego wielką słabością w stosunku do np. Gita czy Bazaar-a, które dzięki swojej elastycznej architekturze oferują wiele przeróżnych sposobów organizacji pracy z repozytorium.

Modele pracy są jednym z wielu argumentów, dla których warto rozważyć przesiadkę na inny system kontroli wersji. Polecam zapoznać się z artykułami Why Switch to Bazaar? – Any Workflow albo Workflows – Bazaar Version Control oraz Why Git is Better than X – Any Workflow.

Ja pracuję już kilka lat z Subversion i większość firm z którymi współpracuję lub też współpracowałem też używa SVN. Dlatego decyzja o zmianie systemu wersjonowania najczęściej nie leży w mojej gestii.

Co mogę zatem zrobić? Zarówno Bazaar (bzr-svn) jak i Git (git-svn) mają narzędzia umożliwiające współpracę z Subversion.

Po co łączyć Subversion z Bazaarem lub Gitem

Model pracy rozproszonej oferuje kilka możliwości stanowiących doskonałe uzupełnienie modelu scentralizowanego.

  • Słabe połączenie internetowe albo jego brak nie jest problemem ponieważ wszelkie zmiany dokonywane są lokalnie. Połączenie z serwerem centralnym potrzebne jest jedynie raz na jakiś czas.
  • Niezależne repozytorium, odseparowane i nienarażone na zmiany czynione przez innych użytkowników daje możliwość eksperymentowania. Dokonane zmiany w przypadku powodzenia można później scalić z główną gałęzią lub też usunąć nie zaśmiecając historii zmian centralnego repozytorium.
  • Można ustalić procedurę zgodnie z którą zmiany dokonane w projekcie przez developera trafiają najpierw do osoby nadzorującej projekt, która je sprawdza, testuje i dopiero po akceptacji pcha da SVN-a. W ten sposób do centralnego repozytorium trafią jedynie zmiany stabilne.
  • Warto też wspomnieć o takim prozaicznym powodzie jak brak upierdliwych katalogów „.svn” w katalogu roboczym projektu – małe a cieszy :D .

Praca z Bazaarem jako uzupełnieniem Subversion

Importowanie repozytorium

Ja wybrałem Bazaar z uwagi na moje większe doświadcznie z tym systemem kontroli wersji.

Dla tych, którzy nie mieli jeszcze styczności z Bazaarem proponuję na start prosty tutorial Bazaar in five minutes. Jeśli chodzi o naukę to Bazaar ma tę przewagę nad Gite, że większość jego komend jest identyczna z tymi znanymi z SVN.

Jeśli nie mamy jeszcze zainstalowanego Bazaara (bzr) oraz wtyczki umożliwiającej współpracę z Subversion bzr-svn to w przypadku Ubuntu wystarczy jedynie pobrać wyżej wspomniane z repozytorium i zainstalować.

sudo apt-get install bzr bzr-svn

W przytoczonym wyżej tutorialu nowe repozytorium tworzy się poprzez komendę bzr init. W tym przypadku nie ma takiej potrzeby. Aby „zaimportować” repozytorium SVN do Bazaara należy utworzyć tzw. brancha. Zakładam że znajdujemy się w katalogu roboczym, w którym trzymamy projekty (workspace). Wywołujemy komendę bzr branch i podajemy jako parametry url repozytorium svn oraz nazwę katalogu jaki zostanie stworzony na naszym komputerze i w którym zostanie utworzone lokalne repozytorium Bazaara.

bzr branch svn+http://svn-repository.example.com/project/trunk ./project

Od tego momentu można już pracować z Bazaarem. Dostępna jest pełna historia zmian i jakby się uprzeć to można zapomnieć o SVN-ie ;) (choć do właściwego importu SVN do Bazaar służy komenda bzr svn-import) Dostępne mamy zarówno narzędzia konsolowe, jak też całą kolekcję GUI z których niejako firmowym jest multoplatformowy Bazaar Explorer. Fanom Eclipse polecam z kolei plugin do obsługi Bazaara, który niczym nie ustępuje swojemu odpowiednikowi dla Subversion.

Pracujemy w ten sposób, że wszelkie zmiany w plikach zatwierdzamy (commit) do lokalnego repozytorium. Kiedy zmiany w projekcie przyjmują już stabilną postać jesteśmy gotowi do zarejestrowania wprowadzonych poprawek w centralnym repozytorium SVN. Zanim to jednak zrobimy należy najpierw sprawdzić czy od czasu ostatniego pobrania zmian z SVN coś się nie zmieniło. W końcu najczęściej nie pracujemy sami. Wchodzimy do katalogu naszego projektu i wywołujemy:

Warto sprawdzić czy coś się zmieniło?

bzr pull svn+http://svn-repository.example.com/project/trunk

Jeśli pracujesz w zespole, a poprawka którą miałeś zrobić nie była mała to najprawdopodobniej otrzymasz komunikat, że w repozytorium dokonano zmian. Trzeba je będzie sprawdzić, scalić z lokalnymi zmianami i ponownie zatwierdzić. Bazaar podpowie Ci co masz zrobić.

bzr: ERROR: These branches have diverged. Use the missing command to see how.
Use the merge command to reconcile them.

Scalanie różnic jest proste

Jeśli inni developerzy nie edytowali tych samych plików co ty to zazwyczaj wystarczy:

Do podejrzenia różnic

bzr missing

Do scalenia zmian

bzr merge

Następnie przydałoby się sprawdzić jakie pliki różnią się względem lokalnego repozytorium po scaleniu ze zmianami dokonanymi w repozytorium centralnym

bzr status

Po ich zatwierdzeniu

bzr commit -m 'Treść komunikatu'

Zostaje już tylko wysłanie wszystkiego do svn.

bzr push svn+http://svn-repository.example.com/project/trunk



UWAGA! append_revisions_only error



W tym momencie najprawdopodobniej wyskoczy Ci mały Zonk i otrzymasz taki niemiły komunikat

Using saved push location: svn+http://svn-repository.example.com/project/trunk
bzr: ERROR: Operation denied because it would change the mainline history. Set the append_revisions_only setting to False on branch "svn+http://svn-repository.example.com/project/trunk" to allow the mainline to change.

Niestety komunikat Bazaar nie jest w tym wypadku wyczerpujący gdyż nic nie mówi na temat tego gdzie ustawić append_revisions_only na false.

W Ubuntu wyedytuj plik ~/.bazaar/subversion.conf i dodaj wspomnianą dyrektywę pod adresem repozytorium SVN

[4ef181b9-d188-42c4-ae88-58g6dfg8760b]
locations = svn+http://svn-repository.example.com/project/trunk
append_revisions_only = False

To powinno załatwić sprawę.

Uwaga konflikt!

To był optymistyczny scenariusz. W mniej pomyślnej sytuacji dokonasz zmian w tym samym pliku w którym ktoś inny grzebał i to najprawdopodobniej w tych samych liniach. Automat tego nie rozwiąże. Załóżmy, że chodzi o plik „foo.py”. Pojawia się konflikt a problematyczny plik doznaje cudownego rozmnożenia.

  1. foo.py.BASE – plik w wersji pozbawionej zmian powodujących konflikt (w svn foo.py.rOLDREV)
  2. foo.py.OTHER – plik ze zmianami dokonanymi przez innego użytkownika (w svn foo.py.rNEWREV)
  3. foo.py.THIS – plik z moimi lokalnymi zmianami (w svn foo.py.mine)
  4. foo.py – zawiera to samo co foo.py.THIS

Kilka słów od Kdiff3 – bez niego moje życie było by o wiele bardziej skomplikowane

Każdy ma swoje ulubione narzędzie do scalania różnic. Ja preferuję Kdiff3 – dostępny na Linuksa i Windowsa. Mimo, że zarówno Eclipse jak i Bazaar Explorer mają swoje narzędzia do porównywania zmian ja staram się użyć Kdiff3 którego interfejs jest mi dobrze znany.

Edycja konfliktu przy użyciu Kdiff3 wymaga wywołania w konsoli komendy

kdiff3 foo.py.BASE foo.py.OTHER foo.py.THIS -o foo.py

Oczywiście nie wszyscy lubią konsolę. Aby np. Bazaar Explorer korzystał z Kdiff3 należy wyedytować plik ~/.bazaar/bazaar.conf i w sekcji DEFAULT dodać.

external_merge = kdiff3 %b %o %t -o %r

Jako ciekawostkę kierując się zawodową uprzejmością podaję też sposób wywołania tortoisemerge.

external_merge = tortoisemerge /base:%b /theirs:%o /mine:%t /merged:%r

Kdiff3 można też zintegrować z Eclipse jednak opcję taką znalazłem jedynie dla Subversion. Należy otworzyć Preferencje->Team->Diff/Merge. W sekcji „Conflict Resolution Program” wybrać opcję „External” i wskazać gdzie leży Kdiff3 (u mnie /usr/bin/kdiff3). W polu parameters należy podać

${base} ${yours} ${theirs}  -o ${merged}

Rozwiązaniem konfliktu należy się pochwalić

Po ręcznym rozstrzygnięciu konfliktów należy Bazaar poinformować o tym – analogicznie jak w svn.

bzr resolve foo.py

Komenda „resolve” usuwa przy okazji pliki foo.py.BASE, foo.py.OTHER oraz foo.py.THIS. Teraz wystarczy już tylko zatwierdzić zmiany (commit) oraz pchnąć do centralnego repozytorium (push).

Dobra rada na koniec

Bazaar czy Git to systemy kontroli wersji stworzone do pracy rozproszonej oraz dopracowane pod kątem łączenia osobnych repozytoriów. Mają pod tym względem znaczną przewagę nad Subversion. Model pracy będący mixem korzystającym z rozproszonego repozytorium np. Bazaar oraz centralnego SVN ma swoje zalety jednak stanowi dodatkowy narzut pracy związany z koniecznością dublowania pewnych czynności. Nie należy na siłę wdrażać rozwiązań, które nie są efektywne lub wręcz zbędne. Dlatego jeśli w firmie używającej Subversion stosuje się dopracowane procedury zatwierdzania zmian w repozytorium, nie ma problemów z połączeniem, a modyfikacje w projekcie nie mają charakteru rewolucji będącej jednym wielkim eksperymentem wymagającym tworzenie piaskownicy, być może funkcjonalność Subversion jest w zupełności wystarczająca.

 

PHP 5.3 – wywołanie array_multisort za pośrednictwem call_user_func_array

08 cze

Chcąc dostosować swój kod do wersji PHP 5.3, tak aby wykonywał się bezproblemowo z uwzględnieniem błędów STRICT natrafiłem na taki drobny szczegół. Swego czasu dodałem do manuala funkcji array_multisort na php.net taką drobną [notkę zawierającą implementację funkcji ułatwiającej sortowanie wyników zapytań sql-owych] (http://usphp.com/manual/en/function.array-multisort.php#87268).

Chcąc ją dzisiaj użyć dostałem na twarz warning-a „Parameter 2 to array_multisort() expected to be a reference, value given”.

Załóżmy, że miałem następujące dane.

$data = array(
	0 => array (
		'id' => '1',
		'name' => 'Rodzaje',
	),
	1 =>
	array (
		'id' => '2',
		'name' => 'Kategorie',
	),
	2 =>
	array (
		'id' => '3',
		'name' => 'Statusy',
	),
	3 =>
	array (
		'id' => '4',
		'name' => 'Kolory',
	),
);

Aby posortować tę tablicę według kolumny „name” wywołałem wspomnianą funkcję w następujący sposób

sortDbResult($data, 'name', SORT_ASC, SORT_STRING);

Przyjrzałem się problematycznej linii i zobaczyłem, że wywołuję funkcję array_multisort przy pomocy funkcji call_user_func_array, do której parametry przekazuję za pośrednictwem tablicy.

call_user_func_array('array_multisort', $_params);

W moim przypadku zmienna $_params miała następującą zawartość

array(
0 => &array (
	0 => 'Rodzaje',
	1 => 'Kategorie',
	2 => 'Statusy',
	3 => 'Kolory',
),
1 => 2,
2 => 4,
3 => array(
	0 => array (
		'id' => '1',
		'name' => 'Rodzaje',
	),
	1 =>
	array (
		'id' => '2',
		'name' => 'Kategorie',
	),
	2 =>
	array (
		'id' => '3',
		'name' => 'Statusy',
	),
	3 =>
	array (
		'id' => '4',
		'name' => 'Kolory',
	),
));

Pomyślałem sobie o co chodzi z tym błędem w końcu drugi parametr funkcji array_multisort to w moim przypadku wartość stałej SORT_ASC czyli 2. Przeprowadziłem mały eksperyment i wywołałem funkcję array_multisort bezpośrednio.

$data_1 = array (
	0 => 'Rodzaje',
	1 => 'Kategorie',
	2 => 'Statusy',
	3 => 'Kolory',
);
 
$data_2 = array(
	0 => array (
		'id' => '1',
		'name' => 'Rodzaje',
	),
	1 =>
	array (
		'id' => '2',
		'name' => 'Kategorie',
	),
	2 =>
	array (
		'id' => '3',
		'name' => 'Statusy',
	),
	3 =>
	array (
		'id' => '4',
		'name' => 'Kolory',
	),
);
array_multisort($data_1, SORT_ASC, SORT_STRING, $data_2);
 
var_dump($data_2);

Zadziałało. Tablica $_data2 została posortowana prawidłowo.

call_user_func_array('array_multisort',  array(&$data_1, SORT_ASC, SORT_STRING, &$data_2));

Powyższy kod również wykonał się nie zwracając żadnych komunikatów błędów.

$params = array(&$data_1, SORT_ASC, SORT_STRING, &$data_2);
call_user_func_array('array_multisort',  $params);

Wykonanie powyższego kodu kończy się już niestety warningiem. Aby się go pozbyć trzeba użyć małego obejścia i przypisać wartości stałych do zmiennych a następnie przekazać je do tablicy przy pomocy referencji.

$o = SORT_ASC;
$v = SORT_STRING;
$params = array(&$data_1, &$o, &$v, &$data_2);
call_user_func_array('array_multisort', $params);

W tym wypadku nie działa ukrywanie błędów. Funkcja array_multisort po prostu nie zadziała prawidłowo.

Poprawiona funkcja sortDbResult wygląda następująco:

/**
 * Sort DB result
 *
 * @param array $data Result of sql query as associative array
 *
 * Rest of parameters are optional
 * [, string $name  [, mixed $name or $order  [, mixed $name or $mode]]]
 * $name string - column name i database table
 * $order integer - sorting direction ascending (SORT_ASC) or descending (SORT_DESC)
 * $mode integer - sorting mode (SORT_REGULAR, SORT_STRING, SORT_NUMERIC)
 *
 * 
 *  $i,
 *                      'first_name' => sprintf('first_name_%s', rand(1, 9)),
 *                      'last_name' => sprintf('last_name_%s', rand(1, 9)),
 *                      'date' => date('Y-m-d', rand(0, time()))
 *                  );
 * }
 * $data = sortDbResult($data, 'date', SORT_DESC, SORT_NUMERIC, 'id');
 * var_dump($data);
 * $data = sortDbResult($data, 'last_name', SORT_ASC, SORT_STRING, 'first_name', SORT_ASC, SORT_STRING);    
 * var_dump($data);
 * ?>
 * 
 *
 * @return array $data - Sorted data
 */

function sortDbResult(array $data /*$name, $order, $mode*/) {
	$_argList = func_get_args();
	$_data = array_shift($_argList);
	if (empty($_data)) {
		return $_data;
	}
	$_max = count($_argList);
	$_params = array();
	$_cols = array();
	$_rules = array();
	for ($_i = 0; $_i < $_max; $_i += 3)
	{
		$_name = (string) $_argList[$_i];
		if (!in_array($_name, array_keys(current($_data)))) {
			continue;
		}
		if (!isset($_argList[($_i + 1)]) || is_string($_argList[($_i + 1)])) {
			$_order = SORT_ASC;
			$_mode = SORT_REGULAR;
			$_i -= 2;
		} else if (3 > $_argList[($_i + 1)]) {
			$_order = SORT_ASC;
			$_mode = $_argList[($_i + 1)];
			$_i--;
		} else {
			$_order = $_argList[($_i + 1)] == SORT_ASC ? SORT_ASC : SORT_DESC;
			if (!isset($_argList[($_i + 2)]) || is_string($_argList[($_i + 2)])) {
				$_mode = SORT_REGULAR;
				$_i--;
			} else {
				$_mode = $_argList[($_i + 2)];
			}
		}
		$_mode = $_mode != SORT_NUMERIC
					? $_argList[($_i + 2)] != SORT_STRING ? SORT_REGULAR : SORT_STRING
					: SORT_NUMERIC;
		// references below required from PHP 5.3
		$_rules[] = array('name' => $_name, 'order' => &$_order, 'mode' => &$_mode);
	}
	foreach ($_data as $_k => $_row) {
		foreach ($_rules as $_rule) {
			if (!isset($_cols[$_rule['name']])) {
				$_cols[$_rule['name']] = array();
				$_params[] = &$_cols[$_rule['name']];
				// references below required from PHP 5.3
				$_params[] = &$_rule['order'];
				$_params[] = &$_rule['mode'];
			}
			$_cols[$_rule['name']][$_k] = $_row[$_rule['name']];
		}
	}
	$_params[] = &$_data;
	call_user_func_array('array_multisort', $_params);
	return $_data;
}
 
No Comments

Posted in PHP

 

Instalacja (downgrade) php 5.2.x w Ubuntu 10.04 Lucid

13 maj

W końcu zdecydowałem się zaktualizować Ubuntu do nowszej wersji 10.04. Ku mojemu zaskoczeniu upgradowi uległ też PHP do wersji 5.3. Nie jest to przeze mnie koniecznie porządane w tym momęcie gdyż mam masę projektów, które nie zadziałają (jeszcze) z PHP w najnowszej wersji. Dlatego koniecznym stał sie downgrade do wersji 5.2. Na necie można znaleść wiele wskazówek jak tego dokonać.

Ja początkowo skorzystałem z artykułu pt. Install (downgrade) php 5.2.x in Ubuntu 10.04 Lucid. Niestety PHP po restarcie Apacha się nie odpalił. Ponieważ czasu miałem mało, nie zagłębiałem się w przyczynę niepowodzenia. Poszukałem i na jednym z forów o Ubuntu znalazłem gotowy skrypt bash-a.

#!/bin/bash
# by Ruben Barkow (rubo77) http://www.entikey.z11.de/
 
# Originally Posted by Bachstelze http://ubuntuforums.org/showthread.php?p=9080474#post9080474
# OK, here's how to do the Apt magic to get PHP packages from the karmic repositories:
 
echo "Am I root?  "
if [ "$(whoami &2>/dev/null)" != "root" ] && [ "$(id -un &2>/dev/null)" != "root" ] ; then
  echo "  NO!
 
Error: You must be root to run this script.
Enter
sudo su
"
  exit 1
fi
echo "  OK";
 
 
# finish all apt-problems:
apt-get -f install
 
# remove all your existing PHP packages. You can list them with dpkg -l| grep php
PHPLIST=$(for i in $(dpkg -l | grep php|awk '{ print $2 }' ); do echo $i; done)
echo these pachets will be removed: $PHPLIST 
# you need not to purge, if you have upgraded from karmic:
aptitude remove $PHPLIST
# on a fresh install, you need purge:
# aptitude remove --purge $PHPLIST
 
 
#Create a file each in /etc/apt/preferences.d like this (call it for example /etc/apt/preferences.d/php5_2);
#
#Package: php5
#Pin: release a=karmic
#Pin-Priority: 991
#
#The big problem is that wildcards don't work, so you will need one such stanza for each PHP package you want to pull from karmic:
 
echo ''>/etc/apt/preferences.d/php5_2
for i in $PHPLIST ; do echo "Package: $i
Pin: release a=karmic
Pin-Priority: 991
">>/etc/apt/preferences.d/php5_2; done
 
# duplicate your existing sources.list replacing lucid with karmic and save it in sources.list.d:
#sed s/lucid/karmic/g /etc/apt/sources.list | sudo tee /etc/apt/sources.list.d/karmic.list
 
# better exactly only the needed sources, cause otherwise you can get a cachsize problem:
echo "# needed sources vor php5.2:
deb http://de.archive.ubuntu.com/ubuntu/ karmic main restricted
deb-src http://de.archive.ubuntu.com/ubuntu/ karmic main restricted
 
deb http://de.archive.ubuntu.com/ubuntu/ karmic-updates main restricted
deb-src http://de.archive.ubuntu.com/ubuntu/ karmic-updates main restricted
 
deb http://de.archive.ubuntu.com/ubuntu/ karmic universe
deb-src http://de.archive.ubuntu.com/ubuntu/ karmic universe
deb http://de.archive.ubuntu.com/ubuntu/ karmic-updates universe
deb-src http://de.archive.ubuntu.com/ubuntu/ karmic-updates universe
 
deb http://de.archive.ubuntu.com/ubuntu/ karmic multiverse
deb-src http://de.archive.ubuntu.com/ubuntu/ karmic multiverse
deb http://de.archive.ubuntu.com/ubuntu/ karmic-updates multiverse
deb-src http://de.archive.ubuntu.com/ubuntu/ karmic-updates multiverse
 
deb http://security.ubuntu.com/ubuntu karmic-security main restricted
deb-src http://security.ubuntu.com/ubuntu karmic-security main restricted
deb http://security.ubuntu.com/ubuntu karmic-security universe
deb-src http://security.ubuntu.com/ubuntu karmic-security universe
deb http://security.ubuntu.com/ubuntu karmic-security multiverse
deb-src http://security.ubuntu.com/ubuntu karmic-security multiverse
" >> /etc/apt/sources.list.d/karmic.list
 
aptitude update
 
apache2ctl restart
 
echo install new from karmic:
aptitude -t karmic install $PHPLIST
 
# at the end retry the modul libapache2-mod-php5 in case it didn't work the first time:
aptitude -t karmic install libapache2-mod-php5
 
apache2ctl restart

Powyższy kod wystarczy zapisać w pliku o dowolnej nazwie np. phpdowngrade.sh, nadac mu prawa wykonalności

chmod +x ./phpdowngrade.sh

… i odpalić.

UWAGA! Aktualizacja PHP przez Synaptica przywróci nam z powrotem wersję 5.3. Doinstalowywanie wszelkich dodatków powinniśmy wykonywać z uwzględnieniem wydania. Najprościej to zrobić uzywając konsolowego programu aptitude.

sudo aptitude -t karmic install php5-mysql
sudo aptitude -t karmic install phpmyadmin
 
3 Comments

Posted in GNOME

 

Motorola Milestone

08 maj

Nareszcie moja. Czekalem dlugo, ale bylo warto. Moje pierwsze wrazenie kiedy dostalem go w swoje rece, to zaklopotanie. Wczesniej nie mialem aparatu z pelna klawiatura „qwerty” nie mowiac juz o ekranie dotykowym. Trzeba siege bylo nauczyc obslugiwac te piekielna maszyne.

Mysle ze wybor telefonu z fizyczna klawiatura byl dobrym pomyslem. Probowalem pisac na wirtualnej, ale bylo to mniej wygodne i do tego ograniczalo wielkosc ekranu. Moim skromnym zdaniem cztery podstawowe przyciski tj. „powrot”, „ustawienia”, „home” i „szukaj” tez mogly by byc fizyczne – tak jak w G1.

Ekran dotykowy to rewelacja tylko te slady paluchow widoczne zwlaszcza pod swiatlo… Chcac byc obiektywnym musze jednak stwierdzic, ze dla osoby czesto odbierajacej telefon, a do tego jeszcze robiacej to w malo sprzyjajacych warunkach („w biegu”, w samochodzie, jedna reka) aparat z ekranem dotykowym nie jest najlepszym rozwiazaniem. Obsluga takiego telefonu wymaga patrzenia na ekran i dosc precyzyjnych ruchow do tego rozmiar fona nie ulatwia sprawy. Inna kwestia jest pojemnosc baterii, ktora wymaga codziennego ladowania. Z drugiej strony mozliwosci jakie daje android warte sa rozwazenia opcji posiadania dwoch telefonow.

Mam to cacko zaledwie tydzien. Do czego zdazylem w Tym czasie uzyc telefonu? – zdobilem pare fajnych fotek i kilka filmikow na komunii chrzesniaka mojej zony – na wyjazd do Norymbergi nie zdazylem sciagnanc map do nawigacji bo kupilem telefon dzien przed wyjazdem, ale w jezdzie po Poznaniu aplikacja motoroli swietnie sie sprawdzila – zsynchronizowalem swoje kontakty z kontem na gmailu oraz facebooku – odebralem poczte z 3 skrzynek mailowych, oraz wyslalem email do kilku znajomych – dodalem kilka wpisow do kalendarza google – wgralem kilkanascie mp3-jek oraz innych plikow korzystajac z aplikacji motoroli, a takze poprzez ftp lub przegladarke internetowa (zarowno pod Windowsem, jak i Linuksem) – wymienilem sie kontaktami uzywajac programu do generowania foto kodu – zainstalowalem kilka przeroznych aplikacji i gier – zmienilem ustawienia swojego kontakt na playmobile – dodaje wpis do bloga postawionego na wordpresie

Nie liczac dwoch gluchaczy, ktore wyslalem dla proby nie wykonalem jak dotad zadnego telefonu.

Telefon w urzadzeniu z zainstalowanym androidem to jedynie jedna z wielu funkcji i jak dla mnie – przynajmniej narazie – nie najwazniejsza.

 
No Comments

Posted in System

 

Jak wydobyć rozszerzenie z nazwy pliku.

06 kwi

Jednym z ważniejszych zabiegów optymalizujących kod aplikacji jest używanie przy wykonywaniu poszczególnych operacji, funkcji do tego dedykowanych. Powszechną jest opinia o nadużywaniu np. wyrażeń regularnych, czy też pisaniu własnych funkcji, których odpowiedniki są już zaimplementowane w samym PHP.

Wydobycie rozszerzenia z nazwy pliku nie jest operacją zbyt skomplikowaną i zasobożerną jednak da się ją wykonać na kilka różnych sposobów. Postanowiłem przeprowadzić mały test sprawdzający, które z przyjętych rozwiązań wykona owo zadanie najsprawniej.

Na początek przedstawię kilka sposobów wyekstrahowania rozszerzenia z pełnej ścieżki do pliku.

Na początek użycie funkcji pathinfo

function get_ext_using_pathinfo($path) {
	$parts = pathinfo($path);
	return $parts['extension'];
}

Użycie funkcji pathinfo ze stałą PATHINFO_EXTENSION – dostępną od wersji PHP 5.2

function get_ext_using_pathinfo_with_const($path) {
	return pathinfo($path, PATHINFO_EXTENSION);
}

Użycie funkcji operujących na tekście substr i strrpos

function get_ext_using_substr_and_strrpos($path) {
	return substr($path, strrpos($path, ".") + 1);
}

Użycie wyrażeń regularnych a dokładnie funkcji preg_replace

function get_ext_using_preg_replace($path) {
	return preg_replace('/.*\.([a-zA-Z0-9]*)$/', '\\1', $path);
}

Użycie wyrażeń regularnych z tymże tym razem funkcji preg_match

function get_ext_using_preg_match($path) {
	preg_match('/.*\.([a-zA-Z0-9]*)$/', $path, $matches);
	return $matches[1];
}

Wykonanie exploda i wydobycie ostatniego elementu tablicy funkcją array_pop

function get_ext_using_explode($path) {
	return array_pop(explode('.', $path));
}

Przez każdą z wyżej wymienionych funkcji – w pętli for – 10 tys. razy przepuściłem zmienną zawierającą przykładową ścieżkę do pliku.

$path = '/home/user/workplace/project/images/file.sufix.ext';

Operację tę wykonałem kilkukrotnie zapisując wyniki do pliku. Po uśrednieniu i zaokrągleniu wyników wyszło mi:

substr i strrpos preg_replace preg_match pathinfo ze stałą PATHINFO_EXTENSION explode i array_pop pathinfo
0.077 0.0822 0.0904 0.0952 0.1049 0.1310

Jak wynika z powyższego zestawienia najlepiej spisały się funkcje operujące na stringach. Funkcje preg_replace i preg_match pozytywnie mnie zaskoczyły gdyż spodziewałem się, że zaprzęgnięcie do tak prostej pracy tak potężnej maszyny jaką są wyrażenia regularne będzie obarczone sporą stratą czasu. Z kolei bardzo zawiodłem się na wbudowanej funkcji pathinfo, którą dotąd najczęściej wykorzystywałem do wydobycia potrzebnych mi informacji ze ścieżki. Myślałem, że jest bardziej wydajna, a tu się okazało, że w wersji uniemożliwiającej użycie stałej PATHINFO_EXTENSION jest ona wolniejsza nawet od exploda. Nie skreślałbym tej funkcji w przypadku chęci uzyskania kompletu danych o ścieżce jednak dla atomowej operacji wydobycia rozszerzenia warto pomyśleć o innym sposobie. Z drugiej strony, różnice jak widać nie są znowu tak wielkie, więc dla tego prostego zadania w 99% przypadków użycia nie będzie miało znaczenia, którego z rozwiązań użyjemy i spokojnie możemy kierować się wygodą.

 
 

Krusader w Ubuntu – jak podpiąć terminal?

29 mar

Krusader jest dydykowany KDE jednak jeśli ktoś lubi dwa panele to równie dobrze można go uruchomić pod GNOME. Konfiguracja nie różni się właściwie od tej pod KDE poza kilkoma drobiazgami. W GNOME domyślnym edytorem jest „gedit” a konsolą „gnome-terminal” w związku z czym w zakładce Ustawienia -> Konfiguracja Krusadera -> Ogólne na karcie Podstawowe operacje w polu Edytor zamiast

internal editor
warto wpisać

gnome
natomiast w polu Terminal zamiast
konsole --workdir %d
powinniśmy wpisać
gnome-terminal --working-directory=%d
.

Tyle że po zapisaniu i wybraniu F2 terminal się uruchomi, ale bynajmniej nie w bieżącej lokalizacji. W Krusaderze jest błąd, który po zapisaniu zmienia %d na %25d czyli dostajemy gnome-terminal –working-directory=%25d. Można ten problem obejść edytując ręcznie plik konfiguracyjny ~/.kde/share/config/krusaderrc. W sekcji [General] wpisujemy

Terminal=gnome-terminal --working-directory %d
Proszę zwrócić uwagę na brak znaku równości „=”.

 
No Comments

Posted in GNOME

 

Udana konferencja 4Developers 2010

26 mar

W tym roku miałem okazję uczestniczyć w konferencji 4Developers. Świetnie przygotowana impreza zarówno z punktu widzenia organizacyjnego, jak i merytorycznego sprawiła, iż te kilka godzin prelekcji uznaję za bardzo dobrze spędzony czas, który przyniósł mi nie tylko masę pozytywnych wrażeń, ale przede wszystkim ograniczył nieco moją zawodową indolencję.

Więcej na ten temat napisałem na stronie wynurzenie.com, gdzie wszystkich Was serdecznie zapraszam.

 
 

Tworzenie obiektów w JavaScript

21 mar

W JavaSripcie istnieje bazowa klasa Object, która stanowi prototyp wszystkich pozostałych obiektów JavaScript. Można jej użyć bezpośrednio do utworzenia obiektu.

    obj = new Object();
    obj.x = 1;
    obj.y = 2;

lub alternatywnie

    obj = {};
    obj.x = 1;
    obj.y = 2;

Nawiasy klamrowe stanowią semantyczny skrót podobnie jak użycie nawiasów kwadratowych (arr = []) może zastąpić arr = new Array(). Tablica czyli Array jest jednym z wielu wbudowanych w JavaScript obiektów podobnie jak Window, Document itd.

Aby utworzyć niestandardowy obiekt należy najpierw zdefinować prototyp Klasy, której instancją dany obiekt będzie. Najprościej utworzyć prototyp metodą konstruktora.

var Foo = function() {
    this.x = 1;
    this.y = 2;
    this.sum = function() {
       return this.x + this.y;
    }
}

W konstruktorze definiujemy właściwości i metody. Nową instancję tworzy się z użyciem operatora new.

    obj = new Foo();
    alert(obj.x);
    alert(obj.sum());

Do właściwości lub metod można się odwołać za pośrednictwem utworzonego w ten sposób obiektu, ale można też pominąć operację przypisania do zmiennej i wywołać metodę w sposób niemożliwy np. w PHP.

	alert(new Foo().sum());

Wywołując obj = new Foo(); powołuje się do życia instancje prototypu Foo. Można następnie wywołać metodę obj.sum();. Metodę sum można też wywołać z pominięciem przypisania obiektu do zmiennej new Foo().someMethod(); Tak czy inaczej zawsze w trzeba w pierwszej kolejności utworzyć obiekt.

Definiowanie klas metodą prototypu jest łatwe i intuicyjne, nie mniej w przypadku powoływania wielu obiektów danego prototypu zalecany jest sposób definiowania metod z użyciem prototype (nie mylić z frameworkiem prototype).

var Foo = function() { 
    this.x = 1;
    this.y = 2;
};
 
Foo.prototype.sum = function() {
   return this.x + this.y;
}

Różnica polega na tym, że w pierwszym przypadku przy powoływaniu do życia nowej instancji za każdym razem metoda „sum” tworzona jest na nowo, a w drugim przypadku jest to cały czas jedna i ta sama metoda. Zyskuję się na zaoszczędzonej pamięci co przy bardzo rozbudowanych skryptach nabiera znaczenia.

Zdefiniowanie metody z pominięciem słowa „prototype”:

var Foo = function() { };
 
Foo.sum = function(x, y) {
    return x+ y;
}

… daje możliwość wywołania metody klasy bez tworzenia obiektu Foo.sum(2,4); – to taki jakby odpowiednik metod statycznych w PHP. Analogicznie do metod statycznych w PHP użycie „this” wewnątrz takiej funkcji mija się z celem, więc gdybyśmy przez przypadek zdefiniowali:

var Foo = function() { 
    this.x = 1;
    this.y = 2;
};
 
Foo.sum = function() {
   return this.x + this.y;
}

to wywołanie Foo.sum(); zwróci „NaN” a z kolei new Foo().sum(); zakończy się błędem „TypeError on line 1: (new Foo).sum is not a function”.

W JS można też utworzyć obiekt ad hock

var Foo = { x: 1, y: 2, sum: function () { return this.x + this.y; } } W tym wypadku Foo nie jest prototypem tylko instancją prototypu Object dlatego oczywistym jest wywołanie Foo.sum(); z pominięciem operatora new.

 
 

perfectionorvanity.com – powrót po latach

19 mar

Mówiąc krótko Piotr Petrus znów nadaje. Jeden z nielicznych blogów o tematyce webdeveloperskiej, które z chęcią czytałem z uwagi na wartość merytoryczną i estetyczną ginął powoli gdzieś tam w mrokach zapomnienia i myślałem już, że jego autor nigdy nie wznowi swojej Twórczości zagoniony obowiązkami dnia codziennego, pędem za karierą, pieniędzmi … ;) . To żart oczywiście. Nie mniej bardzo się cieszę, że pojawiły się nowe wpisy na perfectionorvanity.com i wierzę, że stare wpisy zostaną przywrócone bo jak widzę, gdzieś się zadziały

 
 

Dropbox KDE

11 mar

Instalacja Dropboxa w Ubuntu to banał. Wystarczy wyedytować listę repozytoriów:

sudo gedit /etc/apt/sources.list

wkleić adresy repozytoriów Dropboxa

deb http://linux.dropbox.com/ubuntu karmic main
deb-src http://linux.dropbox.com/ubuntu karmic main

i zainstalować pakiet nautilus-dropbox

sudo apt-get install  nautilus-dropbox

Pakiet po zainstalowaniu pojawia się w menu->internet. Wystarczy uruchomić i postępować zgodnie z instrukcjami uruchomionego wizarda. Po przelogowaniu mamy działającego i synchronizującego pliki Dropboxa.

W KDE nie mamy jednak nautiliusa a Dropbox nie oferuje pakietów dla Dolphina o Krusaderze nie wspominając. Co zatem? Alternatywne metody instalcji opisane są w zakładce TipAndTricks na stronie Dropboxa.

Mając zainstalowane Kubuntu operacja nie jest tak trudna jakby się można tego spodziewać po oficjalnym „poradniku”.

Przede wszystkich wchodzimy do katalogu domowego.

cd ~/

Następnie przy pomocy wget-a ściągamy klienta 32 lub 64 bitowego.

wget -O dropbox.tar.gz http://www.dropbox.com/download?plat=lnx.x86

Ściągnięte archiwum rozpakowujemy

tar -zxof dropbox.tar.gz

W katalogu domowym powinien nam się pojawić katalog .dropbox-dist. W tym momencie archiwum można już usunąć. Aby uruchomić Dropboxa wystarczy wywołać

~/.dropbox-dist/dropboxd &

znak „&” na końcu komendy spowoduje uruchomienie w tle

Lepiej jednak utworzyć link w autostarcie KDE dzięki czemu Dropbox wystartuje każdorazowo wraz z X-ami.

ln -sf ~/.dropbox-dist/dropboxd ~/.kde/Autostart/

Wzrokowcom polecam filmowy tutorial.

W Nautiliusie po wrzuceniu pliku do Dropboxa z menu kontekstowego można wybrać internetowy adres do udostępnionego w ten sposób zasobu i podesłać go znajomemu mailem lub też wkleić w okno komunikatora. Po wejściu na podany adres w oknie przeglądarki znajomy będzie mógł zobaczyć opublikowane przez nas zdjęcia lub też ściągnąć plik. W Dolphinie taką funkcjonalność możemy uzyskać dzięki niewielkiemu programowi dropbox-servicemenu-kde.

Po ściągnięciu ze strony paczkę należy rozpakować, wejść do katalogu z narzędziem i zainstalować wywołując komędę.

chmod 755 install.sh
./install.sh

Skrypt ściągnie niewielki programik napisany w Pythonie, który wzbogaci menu kontekstowe Dolphina o dodatkowe opcje.

Właściwie jedyne czego brakuje to ikonek wskazujących stan synchronizacji poszczególnych plików i katalogów. Poza tym funkcjonalność Dropboxa w KDE nie odbiega od tej w Ubuntu.

 
No Comments

Posted in KDE