За дизела на Марешки

от Ясен Праматаров
лиценз CC BY

Из автомобилните форуми нещо се заговори в последните месеци за прословутия дизел на Марешки. Колко било изгодно, дали бил добър, кой щял да зарежда там, защото оня бил “борец с вятърните картелници” и кой нямало да зарежда, защото го ненавиждал. Нормално, основната причина е джобно-портфейлна, както и трябва да бъде. Дизелът мирише, но парите – не и както за уважаемия зам. председател на парламента е важен финансовият баланс на фирмата му, така и за редовия шофьор е важно колко парички отлитат от портфейла му. Ако всички имаха правилно понятие какво всъщност са парите и разбираха как работи то, светът щеше да е едно по-добро място.

Така че говорим за пари, за спестен ресурс от гледна точка на самия шофьор – нека видим какво се спестява и какво се харчи, без да залитаме в излишни предизборни пропаганди. Най-малкото – изборите нали минаха.

Всеки трябва да си направи сметката, защото не винаги е толкова “на плюс” – аз отидох за проба и налях пълен резервоар на Еспаса. Засякох колко ми изгоря от единия край на София до другия (при това не бях в най-пиковия час и задръстванията) – 3 литра по бордкомпютър, отиване и връщане (реално може да има лека разлика, а и там в Люлин направих едно кръгче през кръговите, докато намеря откъде се влиза, но най-много да падне до 2.5).

За сравнение, най-близкото Еко е максимум 1 литър отиване и връщане, даже като няма задръстване, го пиши 0.5 литра. В Еко имам карта и в почивен ден с отстъпката дизелът ми идва за 2.03 лв. На Марешки е 1.89 лв. Разлика 14 ст. на литър.

Като пресметнах и изхабеното гориво за път и като теглих чертата, се оказа, че за 72 литра (не съвсем пълен резервоар, но пък няма да ходя до другия край на града на изпарения, все пак) съм спестил… 6 лева… И съм изхарчил общо към два часа от времето си. Голям минус за мен е, че не работят с банкови карти (оправданието, че щяло да оскъпи ми е несериозно, 100% истинската причина е друга, просто знам, че няма как да оскъпи толкова). Трябваше преди пътешествието да ходя да търся банкомат на банката ми, за да тегля кеш и да ги нося в джоба си, все едно сме в 90-те (хе, ама пък тогава нямах пари). Да, там имали банкомат, ама ако бях платил и таксата за теглене от чужд банкомат, от тия 6 лева спестени щяха да останат по-малко от 5…

За хората от град Лаолин ;) е песен, знам. Лошо няма. Но за мен от другата страна на центъра просто няма смисъл – нито е изгодно, нито пък съм някакъв фен на Марешки, та да ходя заради това.

Всъщност и не искам в моята страна на града да се строи такава грамадна бензиностанция, такива неща са за покрайнините или за в полето – ако строи другаде, да ги прави по-малки, нищо не му пречи да печели от оборот и с по-малка площ. Да си сложи ПОС-терминали и пак ще върви бързо.

Така че има влакове за всички пътници, просто за някои пътници има специални влакове и тая бензиностанция е такава, поне от маята камбанария. ;)

„Ливингстън“ най-накрая преодоля своята „черната котка“

от Куинс Парк България
лиценз CC BY-SA

През този сезон „Куинс Парк“ се оказа „черна котка“ на пътя на лидерите в Лига 1 „Ливингстън“, като успя на няколко пъти да ги накаже изненадващо. В последния мач за сеозна между тези съперници обаче изненада нямаше.

„Ливингстън“ спечели домакинството си убедително с 4:0. Резултатът обаче заблуждава относно реалното развитие на срещата. Разликата съвсем не беше така фрапантна между двата съперника. Те създадоха множество голови положения в един мач на надиграване. Домакините откриха резултата в 18 минута, като за тях се разписа младият български нападател Николай Тодоров. След този гол играта се движеше равностойно чак до 70 минута, когато Мълън покачи на 2:0. Оттук изглежда настроението в играта на „паяците“ изчезна, концентрацията им падна. „Ливингстън“ не проявиха милост и се възползваха максимално от откритата игра, като през 10-на минути вкараха още два гола. Така Мълин в 80-та и Кадън в 90-та минута оформиха крайния резултат 4:0.

„Ливингстън“ – „Куинс Парк“ 4–0
1:0 Тодоров – 18′, 2:0 Мълън – 70′, 3:0 Мълин – 80′, 4:0 Кадън – 90′

„Куинс Парк“: 1. Мюър, 2. Митчъл (55′), 3. Фой (54′), 4. Маккърнън, 5. Макгийвър, 6. Къминс, 7. Галт, 8. Брейди, 9. Заната, 10. Маквей, 11. Бърнс (70′).
Рез.: 12. Мортимър, 14. Дохърти, 15. Уортън, 16. Браун, 17. Орси (70′), 18. Макилдъф (55′), 19. Макфърсън (54′).

Ст. „Алмъндвейл“, Ливингстън, 821 зр.

Политиците лъжат, не социологията

от Ясен Праматаров
лиценз CC BY

Помня как Костов загуби изборите. Социолозите казаха, че ще загуби, а той повтаряше “не е вярно, ние имаме наши си проучвания, побеждаваме”. И изгуби.

Сега – пак от същото. Социолозите казваха, че така ще стане, но не – “ние си имаме наши проучвания, и двете коалиции минават бариерата”. И изгубиха.

Как може повече да вярвате на предизборни обещания, отколкото на статистика и математика? Казват ти, че ще изгубиш и ти вместо да събереш всички сили, да се обединиш без оглед на ляв, десен, либерал, консерватор, а с оглед на това че сте против мафията – вместо това ти си повтаряш “ние си имаме наши проучвания, спокойно” и завличаш едни гласове в небитието.

Ами, евала. Това, ако го правиш искрено и не за пари, значи си идиот и не ставаш за политик. Ако го правиш за пари и за да отвееш гласове – пак не ставаш за политик. И ти, и другият като теб.

Правата като привилегия, Хайнлайн и България

от Ясен Праматаров
лиценз CC BY

Минаха още едни избори, в които статуквото спечели. Всички знаем, че не е някакво добро и златно статукво, всички мрънкаме колко зле било, как всички искат рушвети, не си вършат работата и само гледат да се намърдат в някоя схема и да се краде. Всички знаем, но пак статуквото спечели. Как спечели – със свободни избори… иди го разбери…

Зная, че образователният избирателен ценз е едно от тия неща, “за които не се говори”, но във вечери като тази се чудя дали наистина има смисъл да се дава избирателно право на хора, които злоупотребяват с него. Които или търгуват с него, или го принизяват и обезсмислят, като не прилагат нужното усилие на ума и морална преценка, за да изберат кое наистина е по-доброто за обществото. Защото избирането на представители и делегирането на управленски права е точно това – решаване на бъдещето на обществото, а не някаква глупава телевизионна игра с проценти и иха-уха, нашият човек влезе.

Понякога си мисля, че освен ценз на основата на възраст и гражданство, трябва да има и друг начин избирането да бъде защитено. Трябва да има начин избирането да бъде припознато като важно, ценно и ако щете социално определящо.

Чак сега разбирам Хайнлайн в “Звездни рейнджъри”, която миналата есен ми се видя претенциозна и философски неиздържана книга, но сега ми е ясно какво е имал предвид. Екзистенциално ясно, изживявам го – разочарованието и подигравката с гражданското право от хора, които не са положили усилия да преценят ползите и вредите за обществото от дадено гласуване, може да бъде избегнато или с цялостна промяна на нагласите на народа, някакъв вид масово образование, пробуждане, ако щете, или със силово ограничаване. Ограничаване на правата, което да ги направи по-скъпи и човек да трябва да се труди, за да заслужи правото да бъде гражданин, който избира.

Да, звучи крайно, а пък е и фантастика, но все пак когато за пореден път виждаш как народът ти продължава да гласува за потисниците си, човек се замисля дали пък не е добре хората да трябва да заслужат правата си. Правата да избират имам предвид, правата да могат да определят бъдещето, а не другите права, свързани с живота им като индивиди. Живей си, пътувай си, дишай, обичай, говори – но правото да казваш как да живеят другите някак не ми се вижда да е много базисно и изначално… А ако трябваше да го заслужим, ако трябваше да се борим за него и можеше да ни бъде отказвано, тогава дали щяхме да го използваме безразсъдно?

Знам, денят е такъв, затова ги мисля тия неща. Иначе в една нормална страна не липсата на ценз е оправдание, а липсата на убедителност, мисъл и личен пример у политиците.

Но все пак, да чуем Хайнлайн:

“Man has no moral instinct. He is not born with moral sense. You were not born with it, I was not – and a puppy has none. We acquire moral sense, when we do, through training, experience, and hard sweat of the mind.”

“Social responsibility above the level of family, or at most of tribe, requires imagination– devotion, loyalty, all the higher virtues — which a man must develop himself; if he has them forced down him, he will vomit them out.”

“Citizenship is an attitude, a state of mind, an emotional conviction that the whole is greater than the part…and that the part should be humbly proud to sacrifice itself that the whole may live.”

“Under our system every voter and officeholder is a man who has demonstrated through voluntary and difficult service that he places the welfare of the group ahead of personal advantage.”
― Robert A. Heinlein, Starship Troopers, 1959

По-късният Хайнлайн май разбира, че така не стават нещата и подобни схеми най-много да бъдат разбрани криво и с тях да се укрепят вътрешно всякаквите терористи и комунисти, които той ненавижда искрено.

Идеята за заслужаване на гражданското право не е развита повече, нито е популярна в реалния свят – и така може би е правилно. Но отново – има дни, в които ти се иска самата система да прочиства себе си от неправилната употреба на гласуването, а не само да се разчита на плакати за нарушенията и залъгване с предизборни обещания.

Безконцертно настроение

от Ясен Праматаров
лиценз CC BY

Мислех да ходя на концерт на Accept и Sabaton, но пропускам. Не е първият концерт, който пропускам от вече доста години. Нищо, гроздето е кисело, пък и Аксепт без Удо си е нещо като песен на Сабатон за швейцарската гвардия и разграбването на Рим, сложена във видео с немски танкове…

Основно ще си слушам музиката, както досега. Но трябва да водя и децата, ето едно от малките изключения в проточилата се концертна суша беше със Светко на БТР в Троян и на него му хареса много. Ходят да слушат и се занимават с класика, ще е време и за малко рок.

А концертът сега… ами той последно щял да бъде в една зала в Интерекспо. Как пък няма истински читава зала за рок концерти в София? Фестивална кънти, Зала 1 има няколко спота, другото е ехо и мазане, други като Универсиада, Зимния и Ботев са си баскетболни игрища. Ето – може да съборят безмисления стадион до Ариана и да направят една голяма и хубава рок сцена.

Ама как да стане в страна, в която пияните запалянковци са повече от меломаните…

Флекс в неделя сутрин: заглавие с линии от ляво и дясно

от Гонзо
лиценз CC BY-NC-SA

Не знам дали ще има и други публикации, че да се превърне това в рубрика, но ми хареса идеята да си поиграя с флекса в неделя сутрин. И така, искаме на направим заглавка, която има от ляво и от дясно линии до края на блока със съдържание и искаме да го направим с минимален брой елементи. С флексбокс става с точно един елемент. С помощта на двата псевдоелемента ще нарисуваме линиите, а флексбокс ни е нужен, за да подравним нещата. Тайната е в това, че ако флекс контейнера съдържа текст, около него се създава анонимен елемент, който да служи като флекс елемент, и така не ни е необходим допълнителен елемент около текста. Най-добре да ви покажа кода:

HTML:

<h1>Флекс в неделя сутрин</h1>

CSS:

h1 {
  display: flex;
  flex-flow: row nowrap;
  align-items: center;
}

h1:before, h1:after {
  content: '';
  flex: 1;
  height: 0;
  border-top: 1px solid currentColor;
}

h1:before {
  margin-right: .5em;
}

h1:after {
  margin-left: .5em;
}

Резултата:

Флекс

Ако има нещо неясно, питайте!

Невидимо вграждане на външно съдържание с iframe

от Гонзо
лиценз CC BY-NC-SA

Поради различни съображения понякога се налага да използваме външни услуги за част от съдържанието в сайта. В един точно такъв случай ми се наложи да вградя външното съдържание в сайта с iframe и решението трябваше да отговаря на следните изисквания:

  • Височината на iframe-а винаги да отговаря на височината на вградената страница, за да няма втори скролбар.
  • При навигация във вградената страница да се променя и адреса в основната, като промененият адрес да зарежда съответната страница от външната услуга.
  • Заглавието на документа да се променя заедно със навигацията във вграденото съдържание.

Особеното е, че при зареждане на съдържание от друг домейн в iframe JavaScript от едната страница няма достъп до другата. Поради тази причина оразмеряването на iframe според съдържанието изглежда на пръв поглед проблемно. След малко търсене на най-доброто решение се оказа, че то лесно ще ми помогне за изпълнението и на другите две изисквания. Добре де, за втората точка пипнах малко и бекенда на основния сайт, но няма да навлизам в подробности, защото там не съм в свои води.

И така, най-разумното решение за изравняване на височината на iframe с неговото съдържание, когато то се зарежда от друг домейн, е чрез postMessage. Всеки път, когато се зареди страница в рамката, тя праща съобщение към родителската страница с височината на съдържанието. Родителската страница съответно като получи такова съобщение оразмерява рамката.

Вътре в рамката имаме това:

window.addEventListener('load', function(e){
  if(window.parent && window.parent.postMessage){
    var height = document.body.scrollHeight;
    window.parent.postMessage(height, '*');
  }
}, false);

А в основния сайт имаме това:

window.addEventListener('message', function(e) {
  var data = e.originalEvent.data;
  if (!data) return;
  document.getElementById('theframe').style.height = data + 'px';
}, false);

И след като можем да си изпратим някакви данни от единия прозорец към другия, тогава защо не си изпратим всички данни, от които имаме нужда? Какво ни трябва още? Адреса на страницата в рамката и заглавието на страницата. Всъщност няма да ни трябва целия адрес на страницата, а само пътя. Решението ми за синхронизиране на адресите на двете страници беше да добавя пътя от рамката като параметър към адреса на основната страница, и да го използвам за формиране на атрибута src на рамката при зареждане на страницата. Естествено, включих параметър като част от пътя в адреса на основната страница чрез URL Rewrite.

Това, което пропуснах е как точно ще променим адреса на основната страница като получим съобщението от рамката? В първия момент опитах да използвам history.pushState() – имаме навигация и искаме да дадем възможност потребителя да се върне назад и после напред и… имаше обслужване на събитието popstate и се увъртех като пиле в кълчища. Стана така, защото не взех предвид факта, че навигацията вътре в рамката прави записи в историята на браузъра и чрез pushState аз ги дублирам. Много по-лесно се оказа да използвам history.replaceState() – бутоните на браузъра за навигиране в историята управляват рамката, а чрез събитието popstate и postMessage данните за това се пращат към основната страница. Крайният код придоби следния вид:

iframe.js

function sendParent(e){
  if(window.parent && window.parent.postMessage){
    var height = document.body.scrollHeight,
        path = document.location.pathname,
        title = document.title;
    window.parent.postMessage({height: height, path: path, title: title}, '*');
  }
}
window.addEventListener('load', function(e){
  sendParent();
}, false);
window.addEventListener('message', function(e){
  var data = e.data || e.originalEvent.data;
  if(data == 'get') {
    sendParent();
  }
}, false);
window.addEventListener('popstate', function(e){
  setTimeout(sendParent, 0);
}, false);
document.addEventListener("page:load", function() {
  sendParent();
}, false);

parent.js

var theframe = document.getElementById('theframe');
window.addEventListener('message', function(e) {
  var data = e.originalEvent.data;
  if (!data) return;
  theframe.style.height = data.height + 'px';
  window.history.replaceState(null, '', '/help' + data.path);
  window.scroll(0, 0);
  document.title = data.title;
}, false);
window.addEventListener('resize', function(e) {
  theframe.contentWindow.postMessage('get', '*');
}, false);

На края на кода на рамката сигурно сте забелязали събитието page:load – оказа се, че услугата, която вграждаме използва turbolinks и това е събитието, което се случва когато turbolinks зареди съдържанието на нова страница. А на края на кода на основната старница трябва да ви е направило впечатление обработката на resize на прозореца – ако се промени размерът му е много вероятно да се промени и височината на съдържанието в рамката и тогава питаме рамката за размера на съдържанието. Сигурно първото нещо, което си мислите е „А що не го закачим направо на resize на рамката?“ – ами щото resize на рамката се случва и когато ѝ зададем нов размер, което ще изпрати още веднъж съобщение към прозореца, той пак ще сложи нов размер на рамката… Е, на втория – третия път спира тоя пинг-понг, ама кому е нужно…

Та те така, получи се съвсем невидимо за потребителя – зарежда се съдържание, линковете в рамката сменят като че ли цялата страница, бутоните „напред“ и „назад“ на браузъра работят както се очаква… Идилия! Бих ви го показал, но още не сме готови с някои други неща, ще сложа линка когато му дойде времето. Вервайте ми!

Инициатива за ремонтиране на църквата "Свети Атанасий" в с.Черничево

от Георги Станков
лиценз CC BY-NC-ND
Фейсбук групата "Черничево" започва кампания за събиране на средства, с които да ремонтираме църквата "Св. Атанасий." Вярваме, че щом е за църквата, заедно можем да се справим. Сегашното положение на храма е тревожно - покривът тече от няколко години, а оградата се руши.  Църквата трябва да оцелее - наследили сме я от хората преди нас, длъжни сме да я предадем на хората след нас. Тя не е

SVG filters and CSS animations don’t play together well in WebKit

от Гонзо
лиценз CC BY-NC-SA

There is one particular day in my life that went into reading everything I could find about applying SVG filters on HTML content in Webkit/Blink and pulling my hair why didn’t my code work. See, I had an element with a SVG filter applied as a URI reference and the filter didn’t appear in Chrome and Opera. I tryed embedding the filter definition into the HTML – didn’t work, I tryed recreating the filter with the filter functions available in CSS – could’t create the same effect, but filters did work. Thet I noticed that the filters shows up while the JavaScript is loading, and after disabling JS throu DevTools the filter was there. And after toggling every single piece of JavaScript on the website on and off I managet to pinpoint the cause of my trobbles – a function that applied a class to the body that triggered an animation on a element that is siblink to the one with the SVG filter applied. Then I remembered reading about Chrome not using the GPU for SVG filters applied with URI, but using it for the shortcut functions in CSS. And then I knew – when applying the animation, Chrome rendered the whole container with the GPU and the SVG filter disappeard. And I did try to use 2d functions for the animation, but Chrome still used the GPU and broke the filter. So, if you ever try to use complex SVG filters together with CSS animation, be prepared for trouble!

I know what you did onbeforeunload

от Гонзо
лиценз CC BY-NC-SA

There are a couple of questions on StackOverflow about distinguishing download links in onbeforeunload event handler, the usual use case being skipping loading animation. The simple solution is to use the download attribute on the link itself, but this can’t be applied for forms. I had the same problem and fortunately I found a solution.

What I did was the obvious thing of checking the properties of the event object, passed to the handler. In Firefox there is explicitOriginalTarget property and when the event is triggered by a form submission, the property is a reference to the submit button (if the form is submitted by pressing the button). In Chrome there is no such property, but there is another one that does the job – srcDocument.activeElement. This also points to the submit button of the form. Internet Explorer on the other hand does not have any of these shortcuts, so I had to use the long reference event.currentTarget.document.activeElement.

So what I did was add a data-download attribute to the form and check for it in the onbeforeunload handler like this:

window.onbeforeunload = function (e) {
  var target = e.currentTarget.document.activeElement;
  if ( target.form ) {
    target = target.form;
  }
  if ( ('getAttribute' in target) && 
       (target.getAttribute('download') != undefined || 
        target.getAttribute('data-download') != undefined) ) {
    return;
  }
  // Show loading spinner or do whatever you need to.
};

The above code does two things – polyfill browsers that don’t support the download attribute and apply similar logic to forms. It works in IE 9, 10, 11 and Edge, latest Firefox and Chrome.