Разкрихте ме! 6
Признавам си – всички коментари написани за мен в Lifestyle.bg са верни! Аз съм масон. Понеже баба ми е туркиня, ние тримата с Ахмед Мерчев и Ахмед Доган планираме да превземем света. Това трябва да стане до няколко години. Ние сме членове на тайния орден на Силиконовия бюст на Мара Отварачката. Баща ми е Никоай Добрев, той всъщност е тринадесетата рейнкарнация на Буда. А прадядо ми е Смърт. Той е член на сектата на Тери Прачет. Книгата Малки Богове е написана специално с цел да се подкопаят основите на Православната църква. По този начин по българските земи ще започне да се практикува тайната масонска религия. Този процес вече е започнал, а сбирките си ги правим в едно мазе в село Мало Бучино. Там при пълнолуние пренасяме в жертва по едно малко бяло детенце. Примамваме го от специално направеното за целта 101 СОУ Бачо Киро. Ребърцата му изяждаме с масло и чесън. За прикриване на тази дейност работим съвместно с Bastun Networks. Те разработват и внедряват опасни оръжия за агентите ни под прикритие, като Кака Сийка например. Тя е двоен агент на Щази и всъщност работи за нас. Това, че съм роднина на Смърт си личи по белите кичури в косата ми. Заедно със Сотир работим за циганизацията на България. За целта се опитваме да създадем изкуствен интелект, така че хората да престанат да мислят. В тази дейност ни помага и гуруто на пролог, урду и пащу – Владимир Смоленски. И двамата с него сме четвърти братовчеди на Юлиян Вучков. Връзката ни с тъмните комунистически сили разбира се е Светлин Наков. Както се вижда от връзката на страницата, той получава награда от неизвесна социалистическа фигура с тъмна маска. Поводът е разпространяване от негова страна на изключително опасно учение. Понеже сме адаши, моята фирма е част от обръча фирми на Цар Киро, който активно работи за алкохолизирането на нацията. Тези избори ще бъдат провалени от Извънземните. Предсказвам тяхното идване в изборната нощ. Молете се, само избраните ще оцелеят!
Майстор Димитър Софиянлията 9 2
Искам да кажа на дамата с кучетата, че това което прави в момента не е хубаво. Ние сме едни изключително търпеливи хора, но търпението ни е на път да се изчерпа. Ако предположим, че търпението ни е една 50 тонна тежест, от въжето на което виси тази тежеста са останали само няколко тънки косъмчета. Тази тежест е на път да падне в нейната градинка. Някак я понасяме, вече трета година. Искам за пореден път да й напомня, че тя не живее на луната. И това, че си мисли, че може да дразни целия квартал без никакви последствия е изключително лоша заблуда.
- Не сме я абонирали за най-новите порно списания
- Не сме й изпратили комплект вибратори с наложен платеж
- Не сме й нарисували със спрей вратата на гаража
- Не сме й спрели GSM/WiFi/TV сигналите
- Не сме й пуснали 220V по оградата
- Дори не сме й намазали дръжката на вратата с нещо лепкаво и миришещо лошо
Не сме, обаче можем. Можем да бъдем изключително гадни и за сметка на това – за дълъг период от време. Защото очевидно това което иска тя е война. Тази война обаче ние щя я спечелим. Защото сме повече хора и сме по-готини. Ако не е чела A Series of Unfortunate Events на Lemony Snicket, може би сега е най-подходящия момент да ги прочете. В съсвем скоро време ще започнат да й се случват изключително необичайни неща. Но нека бъдем разумни, най-любезно я молим –
РАЗКАРАЙТЕ ДВАТА ПОМИЯРА НЕЗАБАВНО!
Разширяване на TinyScheme със SQLite 5
TinyScheme е един много малък Scheme интерпретатор, който през годините е използван за най-различни интересени проеки. Част от тях законни, други не особено. Той е написан на C и с помощта на макроси към препроцесора може да бъде компилиран с различна функционалност – според нуждите на потребителите. Естествено в самия интерпретатор е реализиран абсолютния минимум на езика. Очаква се потребителите да дописват каквото им потрябва. На мен ми потрябва база данни. Логичния избор за такава беше SQLite. Поради минималните си размери и простата организация – двете си пасват като дупе и гащи. Една хубава библиотека, която разширява TinyScheme възможностите е TSX. Тя дава възможност за работа със сокети и файлове. Написана е много хубаво и всичко вътре е изключително просто за разбиране. Вместо да правя отделна библиотека реших да допиша тази. За да можем да работим със SQLite са необходими поне следните функции – sqlite-open, sqlite-close, sqlite-prepare, sqlite-bind-text, sqlite-step, sqlite-column-text. Съответно трябва да можем да отваряме нова база и да я затваряме. Да правим sqlite3_stmt, да закачаме стойности към него, да го изпълняваме на отделни стъпки и да можем да вземаме стойностите от SELECT заявките. Естествено има още много полезни SQLite функции, които може да потрябват, но тези са един хубав минимум, от който можем да започнем. Разглеждайки TSX сорс кода, лесно можем да се ориентираме как се пишат TinyScheme функции. Всички функции връщат тип pointer, като параметри им се предават указател към интерпретатора и указател към аргументите на функцията. Цялата TinyScheme функционалност можем да ползваме през първия указател. Ето как изглежда sqlite-open.
pointer foreign_sqliteopen(scheme * sc, pointer args) {
sqlite3 *sqlite;
pointer first_arg;
int retcode;
if(args == sc->NIL)
return sc->F;
first_arg = sc->vptr->pair_car(args);
if(!sc->vptr->is_string(first_arg))
return sc->F;
retcode = sqlite3_open(sc->vptr->string_value(first_arg), &sqlite);
if (retcode == -1)
return sc->F;
return sc->vptr->mk_integer(sc, (ptr)sqlite);
}Най-напред проверяваме дали са ни подадени някакви аргументи изобщо, ако не са връщаме #f. След това вземаме първия аргумент. Понеже аргументите ни се подават, като списък (естествено) първия аргумент на функцията е car на списъка. Проверяваме дали той е низ, ако не е връщаме #f. Понеже повече аргументи не ни трябват – викаме sqlite3_open, като подаваме низ от първия аргумент. По този начин инициализираме sqlite3 указател, който след това връщаме. Понеже нямаме специален тип за sqlite3 в TinyScheme, използваме mk_integer(). Тоест връщаме стойността на указателя, като int или long стойност, в зависимост от архитектурата. Това най-вероятно не е най-добрия начин за вършене на тази работа, но със сигурност е най-простия. Ако искаме да постигнем дуракоустойчива система, в която да не разнасяме C указатели из Scheme интерпретатора, можем да му допишем базовите типове. Как става това ще опиша след малко. Вече можем да отворим нова база данни, но е добре да можем и да я затворим – sqlite-close.
pointer foreign_sqliteclose(scheme * sc, pointer args) {
pointer first_arg;
if(args == sc->NIL)
return sc->F;
first_arg = sc->vptr->pair_car(args);
if(!sc->vptr->is_number(first_arg))
return sc->F;
sqlite3 *sqlite = sc->vptr->ivalue(first_arg);
sqlite3_stmt *pStmt;
while((pStmt = sqlite3_next_stmt(sqlite, 0)) != 0 ) {
sqlite3_finalize(pStmt);
}
sqlite3_close(sqlite);
return sc->T;
}Тук си вземаме обратно C указателя, за целта проверяваме дали единствения аргумент е integer. Преди да затворим базата, затваряме и освобождаваме всички sqlite3_stmt отворени към нея. Това ни спестява писане на отделна функция за тази работа. Следваща функция, която ни трябва е sqlite-prepare, тя ще създава sqlite3_stmt обектите (prepared statements).
pointer foreign_sqliteprepare(scheme * sc, pointer args) {
pointer first_arg;
pointer second_arg;
int retcode;
if(args == sc->NIL)
return sc->F;
first_arg = sc->vptr->pair_car(args);
if(!sc->vptr->is_number(first_arg))
return sc->F;
args = sc->vptr->pair_cdr(args);
second_arg = sc->vptr->pair_car(args);
if(!sc->vptr->is_string(second_arg))
return sc->F;
sqlite3_stmt *stmt;
retcode = sqlite3_prepare((sqlite3*)sc->vptr->ivalue(first_arg), sc->vptr->string_value(second_arg),
-1, &stmt, (const char **)NULL);
if(retcode != SQLITE_OK)
return sc->F;
return sc->vptr->mk_integer(sc, (ptr)stmt);
}Тук вече имаме два аргумента на функцията – указател към базата данни и низ – SQL заявка. За да вземем втория правим cdr на списъка, и после отново car. Викаме sqlite3_prepare и ако всичко е наред връщаме указател към sqlite3_stmt. Трябва да можем да вържем стойностите към заявката със sqlite-bind-text.
pointer foreign_sqlitebindtext(scheme * sc, pointer args) {
pointer first_arg, second_arg, third_arg;
int retcode;
if(args == sc->NIL)
return sc->F;
first_arg = sc->vptr->pair_car(args);
if(!sc->vptr->is_number(first_arg))
return sc->F;
args = sc->vptr->pair_cdr(args);
second_arg = sc->vptr->pair_car(args);
if(!sc->vptr->is_number(second_arg))
return sc->F;
args = sc->vptr->pair_cdr(args);
third_arg = sc->vptr->pair_car(args);
if(!sc->vptr->is_string(third_arg))
return sc->F;
retcode = sqlite3_bind_text(
(sqlite3_stmt*)sc->vptr->ivalue(first_arg),
sc->vptr->ivalue(second_arg),
sc->vptr->string_value(third_arg),
-1, SQLITE_STATIC);
if(retcode != SQLITE_OK) {
return sc->F;
}
return sc->T;
}Аргументите са три, вземаме ги с необходимото количество car и cdr. Това е малко досадно, но с достатъчно мотаене на разни списъци, човек става силен car, cdr caar, cadr, ... нинджа. Лепим текста за заявката и ако всичко е наред – връщаме #t. Вече можем да я изпълним със sqlite-step.
pointer foreign_sqlitestep(scheme * sc, pointer args) {
pointer first_arg;
int retcode;
if(args == sc->NIL)
return sc->F;
first_arg = sc->vptr->pair_car(args);
if(!sc->vptr->is_number(first_arg))
return sc->F;
retcode = sqlite3_step((sqlite3_stmt*)sc->vptr->ivalue(first_arg));
if(retcode != SQLITE_DONE && retcode != SQLITE_ROW)
return sc->F;
return sc->T;
}Вземаме указател към базата, изпълняваме стъпката и ако всичко е наред – връщаме #t. Остава да напишем sqlite-column-text.
pointer foreign_sqlitecolumntext(scheme * sc, pointer args) {
pointer first_arg;
pointer second_arg;
char *ret;
if(args == sc->NIL)
return sc->F;
first_arg = sc->vptr->pair_car(args);
if(!sc->vptr->is_number(first_arg))
return sc->F;
args = sc->vptr->pair_cdr(args);
second_arg = sc->vptr->pair_car(args);
if(!sc->vptr->is_number(second_arg))
return sc->F;
ret = sqlite3_column_text((sqlite3_stmt*)sc->vptr->ivalue(first_arg), sc->vptr->ivalue(second_arg));
if (ret == NULL)
return sc->F;
return sc->vptr->mk_string(sc, ret);
}Тук подаваме sqlite3_stmt указател и номер на полето, което искаме да вземем от съответната заявка. Ако всичко е наред връщаме стойността на полето, като низ. Следващата стъпка е да опишем имената на всички функции, така че интерпретатора да може да ги намери, когато заредим библиотеката. С други думи – трябва да регистрираме имената на новите символи. Това става във функцията init_tsx() или съответна за модула init функция (init_sqlite(), ако пишем отделен модул).
#ifdef HAVE_SQLITE
sc->vptr->scheme_define(sc, sc->global_env,
sc->vptr->mk_symbol(sc, "sqlite-open"),
sc->vptr->mk_foreign_func(sc, foreign_sqliteopen));
sc->vptr->scheme_define(sc, sc->global_env,
sc->vptr->mk_symbol(sc, "sqlite-close"),
sc->vptr->mk_foreign_func(sc, foreign_sqliteclose));
sc->vptr->scheme_define(sc, sc->global_env,
sc->vptr->mk_symbol(sc, "sqlite-prepare"),
sc->vptr->mk_foreign_func(sc, foreign_sqliteprepare));
sc->vptr->scheme_define(sc, sc->global_env,
sc->vptr->mk_symbol(sc, "sqlite-bind-text"),
sc->vptr->mk_foreign_func(sc, foreign_sqlitebindtext));
sc->vptr->scheme_define(sc, sc->global_env,
sc->vptr->mk_symbol(sc, "sqlite-step"),
sc->vptr->mk_foreign_func(sc, foreign_sqlitestep));
sc->vptr->scheme_define(sc, sc->global_env,
sc->vptr->mk_symbol(sc, "sqlite-column-text"),
sc->vptr->mk_foreign_func(sc, foreign_sqlitecolumntext));
#endif /* defined (HAVE_SQLITE) */Накрая можем да компилираме TSX и да напишем една елементарна тестова програма sqlite.scm:
(load-extension "tsx-1.1/tsx") (define (db-create sqlite) (define query "CREATE TABLE test (a varchar, b varchar)") (define stmt (sqlite-prepare sqlite query)) (sqlite-step stmt)) (define (db-insert sqlite a b) (define stmt (sqlite-prepare sqlite "INSERT INTO test VALUES (?, ?)")) (sqlite-bind-text stmt 1 a) (sqlite-bind-text stmt 2 b) (sqlite-step stmt)) (define (db-select sqlite) (define stmt (sqlite-prepare sqlite "SELECT * FROM test")) (sqlite-step stmt) (define a (sqlite-column-text stmt 0)) (define b (sqlite-column-text stmt 1)) (display (string-append a b)) (newline)) (delete-file "test.db") (define sqlite (sqlite-open "test.db")) (db-create sqlite) (db-insert sqlite "it is" " working!") (db-select sqlite) (sqlite-close sqlite)
Този пример тества всички написани до момента функции. Остана да напиша как се правят нови типове данни в интерпретатора. Описание за това има в документацията към TinyScheme, то е разбираемо, но не е много актуално. Дописването на нови типове си заслужава, ако се налага използване на динамична памет. Във всички написани до тук функции никъде не използвахме явно динамична памет. Такава памет се използва от самия SQLite. По тази причина ако използваме често sqlite-prepare ще направим memory leak, защото използваната памет се освобождава чак когато затворим базата. Този проблем може да се реши, ако напишем функция sqlite-finalize. sqlite-close и sqlite-finalize обаче не са в “духа” на езика Scheme. Много по-добре би било, ако самия интерпретатор се грижи за освобождаването на паметта, с помощта на garbage collector. TinyScheme използва Schorr-Deutsch-Waite link-inversion algorithm, от The Art of Computer Programming, том 1. Тип string от езика може да се използва, като пример за създаване на нови типове данни, които да използват динамична памет. На мен ми трябваше тип BLOB, в който да пазя разни парчета неформатирани двойчни данни. Този тип разбира се, може да се ползва и за записване на такива данни в SQLite BLOB полета. За целта можем да допишем функциите sqlite-bind-blob и sqlite-column-blob.
pointer foreign_sqlitebindblob(scheme * sc, pointer args) {
pointer first_arg, second_arg, third_arg;
int retcode;
if(args == sc->NIL)
return sc->F;
first_arg = sc->vptr->pair_car(args);
if(!sc->vptr->is_number(first_arg))
return sc->F;
args = sc->vptr->pair_cdr(args);
second_arg = sc->vptr->pair_car(args);
if(!sc->vptr->is_number(second_arg))
return sc->F;
args = sc->vptr->pair_cdr(args);
third_arg = sc->vptr->pair_car(args);
if(!sc->vptr->is_blob(third_arg))
return sc->F;
retcode = sqlite3_bind_blob(
(sqlite3_stmt*)sc->vptr->ivalue(first_arg),
sc->vptr->ivalue(second_arg),
sc->vptr->blob_value(third_arg),
sc->vptr->blob_size(third_arg), SQLITE_STATIC);
if(retcode != SQLITE_OK) {
return sc->F;
}
return sc->T;
}За да работи тази функция, в интерпретатора трябва да имаме дефинирани функциите is_blob(), blob_value() и blob_size(). Човек лесно може да си ги напише, като гледа от съответните string функции. Няма да ги пиша тук, защото ще стане много дълго.
pointer foreign_sqlitecolumnblob(scheme * sc, pointer args) {
pointer first_arg;
pointer second_arg;
char *ret;
int len;
if(args == sc->NIL)
return sc->F;
first_arg = sc->vptr->pair_car(args);
if(!sc->vptr->is_number(first_arg))
return sc->F;
args = sc->vptr->pair_cdr(args);
second_arg = sc->vptr->pair_car(args);
if(!sc->vptr->is_number(second_arg))
return sc->F;
ret = sqlite3_column_blob((sqlite3_stmt*)sc->vptr->ivalue(first_arg), sc->vptr->ivalue(second_arg));
len = sqlite3_column_bytes((sqlite3_stmt*)sc->vptr->ivalue(first_arg), sc->vptr->ivalue(second_arg));
if (ret == NULL)
return sc->F;
return sc->vptr->mk_blob(sc, ret, len);
}Ето тук е интересната част. Използваме mk_blob() за да регистрираме новия тип в интерпретатора. Освобождаването на паметта е грижа на garbage collectior-а. Ако искаме да бъдем перфекционисти, освен BLOB можем да напишем sqlite3 и sqlite3_stmt, като типове в езика. Аз обаче не съм си играл да го правя. Дори в този си вид TinyScheme и SQLite представляват доста мощно средство за писане най-различни програми. В момента работя по една data mining система. Тъй като SQLite се използва масово в Mac OS X, iPhone OS и Series 60, написана на TinyScheme тя ще може да работи лесно на всички тези платформи.
Предизборна антиреклама 1
Вчера инсталирах Window$ на една машина. Днес трябваше да я настроя и да инсталирам целия необходим софтуер. За да сложа Privoxy трябваше да отида до Sourceforge. Неочаквано крехката ми психика беше трайно разстроена от озъбените мутри на Иван Костов и Бойко Борисов. Някак успях да не повърна върху клавиатурата. Това било новата антиреклама на някаква никому неизвесна партия. Целта очевидно е да покаже колко са лоши другарчетата. Много се обидих, понеже всички реклами, които съм виждал до момента на Sourceforge са на големи IT корпорации – разбирай IBM, HP, Sun, Oracle и т.н. Явно тези мушмороци бая пари са изръсили за да окачат въпросните мутри там. Разхождайки се без Privoxy по други български сайтове попаднах и на конкурентите антиреклами. Основната разлика между рекламите и антирекламите е, че първите винаги лъжат, а вторите обикновено са верни. В тази предизборна кампания вярвам на абсолютно всички антиреклами, но за съжаление не вярвам на нито една реклама. И на тези избори ще се придържам към твърдата си позиция да не гласувам, както и да съм сляп и глух за всичко що е политика. Както съм казвал и преди – така се живее по-спокойно. Все пак ми е интересно защо през цялата нова история на България няма нито един военен преврат. Мисля, че сега е особено подходящ момент – да се изрине цялта паплач за назидание на следващите. В Турция този подход е работил много добре през годините. За съжаление обаче явно и по високите етажи на армията лапат своя дял от баницата на ЕС. Тези избори май са най-маловажните избори, които съм виждал в тази страна. Понеже България не е независима държава вече повече от 2 години – въпросът за това кой ще краде на власт е все по-малко актуален. Ако нещата се насерат прекалено много винаги от ЕС ще пратят някой чичко (лелка), който да плесне управляващите през ръцете. Никога не съм вярвал, че личностите в политиката имат някакво значение – те са просто едни палячовци, сложени там да ги гледа народа с вратовръзки по телевизията. Нито един от тях не е успявал да се издигне до ранг на личност. Оказа се обаче, че и партиите в политиката нямат никакво значение – “левите” водиха много по-дясна от “десните”. Сега е ред на десния диктатор и на националистите-комунисти. Всичките се движат по най-малкото съпротивление. Оказа се, че всяко явление в България спада към един или повече от следните три случая – некомпетентност, личен интерес, мърлявщина. Удивително е как някой хора и партии успяват да вложат и трите в една и съща работа. Сега с масираната си антиреклама доказват колко са еднакви всичките. Много по-лесно е да се клепе другарчето отколкото да се излезе с нещо конструктивно. Като не можем да се изкараме добри – дай да изкараме другите по-лоши.
Как се прави баня? 1
Пролетта е сезона на строежите и ремонтите. Тази пролет ми се падна да “микроменажирам” правене на баня. Това вклюваше подробно обясняване на майстора точно какво искам, наблюдение как вървят нещата и вземане на важни решения като – “на колко сантиметра да е мивката”. Тръгнах с нагласата, че искам абсолютно нормална, стандартна, българска баня. Оказа се, че такова животно няма, а българските модни тенденции в банята са залитнали в разни странни и необичайни посоки. Този факт наложи дълги преговори с майстора и в крайна сметка бях обявен за селянин.
- Плочките – Избор на плочки голям. Има всякакви плочки, на всякакви цени. Стоят окачени пред магазините на едни метални конструкции и се виждат от далече. Естествено богатия избор на плочки свършва до там. Когато избрах моите се оказа, че нямат достатъчно количество в момента. Дали ще получат – незнаят. Тези плочки били “стара колекция”. Най-вероятно вече не ги правели. 15 минути от живота ми бяха изгубени безвъзвратно в избиране на несъществуващи плочки. Предвидливо попитах от кои има на склад, кои са от нова колекция и кои се произвеждат в момента, преди да започна да избирам отново. Избрах си едни от няколкото вида, които са нова колекция, произвеждани в момента и ги има на склад.
- Сифоните и наклоните – В момента било модерно подът на банята да се прави равен, да няма сифон. Душа да бъде в душ кабина. За целта се предлагат най-различни видове и размери пластмасови конструкции и поддушови корита. Мразя душ кабините, не виждам защо човек трябва да се затваря в пластмасова душегубка за да се изкъпе, при положение, че има нормална баня. Обясниха ми, че по този начин нямало да мокря банята. Не разбирам защо да не мокря банята, не разбирам защо ще си слагам плочки, ако няма да мокря банята. Защо ще й викаме баня, ако няма да се мокри? Започнах от начало с обясненията, че искам баня, с плочки, искам да я мокря и не искам да имам душ кабина, а просто душ. По този начин стигнахме до въпроса за сифоните и наклоните. Тъй като не искам поддушово корито, там където е душа трябва да има сифон и наклон. Понеже банята е голяма искам още един сифон с наклон, извън този за душа. Казаха ми, че така не се правело сега. Това не било модерно, било стара технология. Дори било селско. Избрах да съм селянин с баня, пред това да съм гражданин с душкабина.
- Тоалетна и мивка – От биологична гледна точка, най-добрата на тоалетна е турската. Говоря за онази турска тоалетна, с която бяха покрили България в Брюксел, на онази изложба, за която политиците мрънкаха, че не ни представяла в правилната светлина. Та тази тоалетна е много полезна, защото човек си върши работата клекнал. По този начин си притиска корема и успява да го изчисти напълно. Нещо което не може да стане в положение седнал. Това е една от многото причини хората по планинските села да живеят по 100 години. Една истинска такава тоалетна обаче трябва да има сифон с вода за да не мирише – нещо което се е спестявало преди години. Основния недостатък на тази тоалетна и единствената причина да не си направя такава е, че тя трябва се чисти. Работа с която на никой не му се занимава. 90% от “нормалните” тоалетни обаче също трябва да се чистят. Това вече може да се окачестви, като недомислица при дизайна – неправилни линий, малки наклони, лошо обливане и т.н. За това си взех скъпа, нормална тоалетна на Видима, с бавно падащ капак (падането на капака винаги ме е дразнело). Струва ми се, че ще се чисти добре сама, но няма как да съм сигурен преди да съм я пробвал. Най-важното нещо при купуването на тоалетна е човек да седне на нея. Част от тоалетните са правени само за китайци и манекенки. Мивката също е Видима, вече съм ползвал такава и знам, че е добра.
- Чешмите – От капиталистическо-икономически-модни съображения чешмите за мивки в банята се правят много-много малки. Това води до един идиотски ефект, който винаги ме е дразнел много – чешма с права тръба, 5 см дълга, която тече надолу. Когато това изобретение се монтира на една голяма мивка се получава така, че за да си измие ръцете човек, той трябва да ги набута някъде в края на мивката, където практически няма място за тях. Явно някой все пак е забелязал, че има такъв проблем, защото чешмата която си купих е с течаща под 45 градуса напред вода. Чешмата за душа, която си купих всъщност няма чешма. Тоест няма режим да тече другаде освен от душа. Стори ми се хитро и удобно, никога не съм ползвал теченето отдолу. Душа естествено се сваля и закачва на регулируема стойка. И двете чешми са Видима. На тази марка са й надули страшно много цените, но когато човек се вгледа в детайлите се вижда, че те са най-добрите. Естествено са напускали и разни 30 левови чешмички, на разни неизвесни производители, които изглеждат същите на пръв поглед. Когато човек се вгледа разликата е огромна, но и цената на Видима е тройна.
Както на много други места, така и в баните се залита по разни модни тенденции и се загърбват традициите. За мен гореописаната баня е стандартна, българска баня. Тя е удобна и е по-добра от западните си аналози. Най-големия кошмар на този свят е английска баня. Крайно време е хората да разберат, че не можем просто да копираме технологии отвън, защото в някои случаи те са по-лоши от това което имаме тук.
