Wednesday, 23 December 2009

Wicked Hollywood

Нещо странно се случава в света на звездите напоследък. Хапчетата онзи ден взеха новата си жертва - Британи Мърфи. Първо Хийт Леджър, после Майкъл Джексън, сега и тя. Все предписани лекарства и т.н. Странно е. Още колко ли добри роли няма да видим никога?

Monday, 11 May 2009

На път през годините

Всяко пътуване впечатлява с нещо - красиви гледки, добра компания или неочаквани приключения. А за да си заслужи и да бъде описано е необходимо особено съчетаване на всички тези компоненти.  Още повече качествения снимков материал помага много. Остава само да се отдели време за сядане пред компютъра и ... ето какво с получи в три такива случая:
Тези пътеписи бяха публикувани от моя приятел от George на неговия отличен тематичен сайт Disagi.com

Thursday, 9 April 2009

Tweeeet!

See what happens when too many people twit at the same time:


Very beautiful way of saying "We're sorry that our service sucks right now, but stay tuned!".
Well It could happen virtually to everyone, so thumbs up Twitter.

Saturday, 4 April 2009

Portable Development - XAMPP Control Panel Issue

If anyone has used the PortableApps' tools and particularly the portable web development suite XAMPP from ApacheFriends, may have encountered the following issue.

On the PortableApps site there is a handy tool called "XAMPP Control Panel". It is really good except for one thing. Lets say you just installed the suite on your flash drive. You start the control panel from the PA menu and it initializes just fine. You do your work and go elsewhere. Then on another PC you start again the XAMPP Control Panel from your removable drive and you get this warning:
Current Directory: X:\xampp
Install Directory:
*** WARNING: Directory mismatch ***

or may be as reported here.

There are two things to be said:
  • First - as John T. Haller stated the problem should be solved in the 1.2 version of the XAMPP Launcher. Well I use the 1.3 version and I still experience this issue. While googling the web I stumbled upon this (see the post of Draven from 22. September 2007) funny but extremely easy solution. I say it's funny because it leads to the
  • Second thing to be noted - the XAMPP Control Panel is not a portable tool at all since it relies on hte Windows registry for storing its configuration data. This conclusion is made also in the PortableApps forum (the upper link).
For PCs you're in control this might be the right decision but in the rest of the cases you just might have to work without the XAMPP Control Panel.

Thursday, 29 January 2009

Малка равносметка

Ето измина повече от година отакто върви този блог, а писанията в него нито са много, нито са чак толкова интерсни. Липса на време и вдъхновение? Със сигурност и двете съставки бяха доста дефицитни.
Какво говорят фактите ?
  • Пропуснах да отбележа годишнината на 17-ти (но поне се вписах в месеца), въпреки че ако бях положил малко усилие можех да драсна няколко реда.
  • В списъка с писанията има две чернови започнати доста отдавна (коментар филма "The Dark Night" и описание на това как да си направим собствен вариант на Wikipedia на USB-то) и чакащи една доста силна комбинация от вдъхновение и свободно време да се включи, за да бъдат завършени. Така е - особените теми изискват особено внимание.
  • Като цяло наличието на достатъчно време доста неприятно се уцелва с липсата на вдъхновение по отношение на злободневната тема и обратно. Май на това му казват живот :)
И тъй като този пост общо взето си изчерпа предназначението, да погледнем с надежда в утрешния ден без значение дали си мислите за реалността или дигиталността на дните ;)

Monday, 29 December 2008

Студентската книжарничка и подобни

В магистратурата по "Софтуерни технологии" на ПУ "Паисий Хилендарски" когато се стигне до курсови проекти, независимо дали става въпрос за направата на уеб сайт/онлайн магазин или приложение за бази данни, темата обикновено е свързана с книгите - библиотека или книжарница. Този триместър заданието е комплексно - изисква да се приложат знания и по трите изучавани дисциплини. Иначе казано в онлайн книжарницата (или кой каквото сътвори, защото книжарницата е само кнотролен пример) трябва да е уеб базирано Java приложение, в което да присъстват в една или друга степен следните технологии:
  • HTML + CSS - като представителен слой;
  • JavaScript - най-малкото за валидация на формите;
  • XML - като персистентен механизъм (вместо база данни);
  • JSP и Servlet-и - отново за представителния слой и за изграждане на логиката на приложението;
  • MVC (Model, View, Controller design pattern) - цялостната архитектура на програмата трябва да отговаря на този шаблон за дизайн.
На пръв поглед възможността за създаване на пълна бъркотия изглежда доста реална. Всъщност в наши дни изброените технологии никак не са много, защото реалнте прокети, с които се сблъскват професионалните прогамисти са доста по-сложни и като архитектура (MVC е само част от картинката), и като изисквани технологии. Все пак за начинаещите това е едно доста добро начало и не би било излишно едно рамо в правилната посока. Според мен верния подход не е само един, но няма да разисквам повече. Най-близка до мисловната ми настройка е следната схема:
  1. Стартиране на нов проект като уеб приложение.
  2. Изграждане на механизма за съхранение на данните - оформяне на хранилището за данните в XML файл. Стуктурата му може да се установи в DTD или XML Schema файл, достъпен при необходимост от валидация.
  3. Като добавка може да се напишат Java Beans обектите, който ще подпомагат съхраняването на данните.
  4. Оформяне на вида на приложението (като се започне от индексната страница) - статичните страници могат да са в HTML формат, но динамичните е необходимо да бъдат JSP.
  5. Свързване на страниците и реализиране на функционалностите - разширяване на JSP и HTML страниците, чрез свързването им с реализираните на тази стъпка Servlet обекти. Последните трябва да могат да съхраняват данните в XML с помощта на Java Beans обектите.
  6. Дооформяне на външния вид на страниците посредством CSS, който е приложим както към HTML, така и към JSP файловете.
  7. Довършване на функционалността на страниците, чрез добавяне на JavaScript валидация на полетата за въвеждане на данните.
Тук не са задължителни нито последователността на стъпките, нито грануларността им (броят на степените, на които е разбита задачата). Подробностите по реализиране на всяка от стъпките могат да се видят с примери в документните файлове дадени по време на упражненията и разгледани вече един път там. В крайна сметка сметка изпълнен по този начин проекта би трябвало да е отговаря на MVC шаблона.

Tuesday, 21 October 2008

Бази данни: Една реалистична задача

Тук е споделен PL/SQL скрипт, който може да е полезен (в съответните вариации разбира се) за задача като описаната тук.
Да предположим, че разполагаме с няколко-стотин таблици на Oracle DB Server (с версия примерно > 8.0i)
. На някои (приятел, колега, клиент, ...) е нужно да разполага със списък на стойностите от някои от колоните на част от таблиците в базата. Иначе казано предоставил ни е списък със следния формат:

име_таблица1, име_колона1
име_таблица2, име_колона1
...
име_таблицаN, име_колона1
име_таблицаN, име_колона2
...
Нашата скромна задачка е да разширим този списък с трета колонка, така че формата му да се промени на:
име_таблица1, име_колона1, стойност1
име_таблица1, име_колона1, стойност2
име_таблица1, име_колона1, стойност3
...
име_таблица2, име_колона1, стойност1
...
име_таблицаN, име_колона1, стойност1
име_таблицаN, име_колона1, стойност2
...
име_таблицаN, име_колона2
...
Единственото ограничение е всеки ред от списъка да е уникален, т.е. за всяка двойка таблица-колона да се вземат само неповтарящите се стойности от базата.

Остава преди да пристъпим към самото изпълнение на скрипта, да премислим как ще отработим входа и изхода му. Първо ще споменем за изхода, тъй като решението там е тривиално.
Изход: Може би най-удобния начин за представяне на таблични данни е ... таблицата. Затова още в началото на скрипта (преди още да се декларират променливите) се отделя една секция за следната DDL дефиниция:
DROP TABLE output PURGE;

CREATE TABLE output (
table_name VARCHAR2(100) NOT NULL,
column_name VARCHAR2(100) NOT NULL,
initial_value VARCHAR2(4000) NOT NULL,
CONSTRAINT unique_row UNIQUE (table_name, column_name, initial_value)
);
Разбира се ограничението за уникалност не е задължително да присъства, още повече, че самия скрипт я гарантира.
От друга страна това не може да е крайния изход, който да е необходим на човека дал ни задачата. За щастие работим с Oracle SQL Developer, при който в контекстното меню на всяка таблица ни е предоставена възможността да изведем данните в редица текстови формати. Изборът на крайния формат е според личните предпочитания и нужди и не изисква особено разяснение.
Вход: Нека няма предявено изискване за оптимизирано решение на задачата, но въпреки това като стъпка към него да използваме структурата на Oracle
асоцииран масив. Особеността, която ще приложим е свързана с размерността на входните данни - ще ги превърнем от двумерни в едномерни. Това означава, че ще разположим последователно двойките "таблица-колона" в масива по такъв начин, че самото индексиране да държи сметка за семантиката на данните, т.е. на нечетните индекси ще се намират таблиците, а на четните - колоните. Смисълът на това изкуствено намаляване на размерността на данните е, че се съкръщава използването на един цикъл. Приемаме, че някоя добра фея се погрижила за трансформирането на входните данни (които мога да наброяват хиляди), до инициализирания асоциативен масив показан по-долу. Би могла да се обсъди и възможността за използване на друг скрипт или разширяване на настоящия да върши и тази дейност, но това няма да стане точно тук.
DECLARE
TYPE Extraction IS TABLE OF VARCHAR2(100) INDEX BY binary_integer;
population Extraction;
it NUMBER; -- The iterator
nextit NUMBER; -- The iterator to be incremented with 1
intit NUMBER; -- iterator for the internal loop
countdist NUMBER := 0; -- Number of distinct records of current table
counter NUMBER := 0; -- Number of all the records of current table

TYPE DistinctiveCursor IS REF CURSOR;
dcursor DistinctiveCursor;
val VARCHAR2(4000);

BEGIN

-- Populating the massive associative array:
population(1) := 'table1';
population(2) := 'column1';
population(3) := 'table2';
population(4) := '
column1';
population(5) := '
table2';
population(6) := '
column2';
population(7) := '
table2';
population(8) := '
column3';
population(9) := '
table3';
population(10) := '
column1';

FOR it IN 1..10
LOOP
nextit := it + 1;
IF population.EXISTS(it) AND (MOD(it, 2) != 0) THEN -- iterates only the table names (odd members of the array)
--dbms_output.put_line('Current value for ' || it || ': ' || population(it) || '.');
IF population.EXISTS(nextit) THEN
--dbms_output.put_line('The next value for ' || nextit || ': ' || population(nextit) || '.');
EXECUTE IMMEDIATE ('SELECT COUNT(' || population(nextit) || ') FROM ' || population(it)) INTO counter ;
EXECUTE IMMEDIATE ('SELECT COUNT(DISTINCT(' || population(nextit) || ')) FROM ' || population(it)) INTO countdist;

OPEN dcursor FOR 'SELECT DISTINCT(' || population(nextit) || ') FROM ' || population(it);
LOOP
FETCH dcursor INTO val;
EXIT WHEN dcursor%NOTFOUND;
--dbms_output.put_line('Stoinost: ' || val);

-- Here goes the actual work of the script:
EXECUTE IMMEDIATE 'INSERT INTO output (table_name, column_name, initial_value) VALUES (:v1, :v2, :v3)'
USING population(it), population(nextit), COALESCE(val, '--- NO VALUE WAS FOUND IN THIS OBJECT! ---');

END LOOP;
CLOSE dcursor;
COMMIT;

END IF;

--dbms_output.put_line('### In this table there are total ' || counter || ' rows and ' || countdist || ' of them are unique.');

END IF;

END LOOP;

END;

Тънките моменти в скрипта са коментирани. В коментар е сложен и изхода към конзолата, който може да се използва за дебъг при случай на нужда.
Разбира се написването на този скрипт нямаше да стане без съответния уеб трафик генериран с помощта на Google. От всичко открито (има стотици наръчници за най-продваната база данни) най-голяма помощ ми оказа този блог.