суббота, 8 декабря 2012 г.

WordCount в Sublime

Sublime чудесен. Можно сказать, что проблема отсутствия под linux-ом Notepad++ успешно решена.

Правда был вопрос – насколько можно его использовать для написания всяких текстов. А чтобы в программе писали тексты, она должна уметь подсчитывать символы.

Соответствующий плагин нашёлся сразу, но он не умел посчитывать количество символов. Решил допилить, а заодно разобраться, что у этих плагинчиков внутри.

В результате – целый вечер открытий и удивительных экспериментов. Удивился встроенной консоли, попутно оптимизировал код и исправил баг с полем read_time в настройках.

Обновлённый код успешно merged и залит в основную ветку.

А удивил меня сам алгоритм подсчёта. Их там целых два, причём первый закомментирован:
#=====1
# wrdRx = Pref.wrdRx
# """counts by counting all the start-of-word characters"""
# # regex to find word characters
# matchingWrd = False
# words = 0
# for ch in content:
# # # test if this char is a word char
# isWrd = wrdRx(ch)
# if isWrd and not matchingWrd:
# words = words + 1
# matchingWrd = True
# if not isWrd:
# matchingWrd = False


#=====2
wrdRx = Pref.wrdRx
words = len([x for x in content.replace('\n', ' ').split(' ') if False == x.isdigit() and wrdRx(x)])
На первый вгляд, алгоритм 1 должен работать лучше и экономней. Фактически, перед нами нечто наподобие state machine, и его сложность не больше o(n). В то время как второй алгоритм создаёт кучу новых элементов только для того, чтобы их пересчитать.

На самом деле алгоритм 2 отрабатывает намного быстрее, чем 1. Например, чтобы подсчитать количество слов в “Петербургских трущобах” Крестовского, 2-ому нужно порядка 1 сек., а первому – 2.

Вот вам и оптимизация.

четверг, 22 ноября 2012 г.

Kosher PC

Придумался скрипт для ортодоксальных иудеев, которые сидят под *nix-ом и стараются соблюдать котев штей отийот – запрет писать две буквы в Шаббат.

Надо открыть .profile и вписать в самое начало:

if ([ `date +"%w"` -eq 0 ]) then shutdown -h now fi

Теперь Ubuntu тоже будет соблюдать Шаббат и выключаться, если на календаре седьмой день недели.

четверг, 20 сентября 2012 г.

SQL: Previous Month and Week

Получаем записи за предыдущаю неделю (от понедельника до полуночи с воскресенье на понедельник):

DECLARE @TodayDayOfWeek INT
DECLARE @EndOfPrevWeek DateTime
DECLARE @StartOfPrevWeek DateTime

SET @TodayDayOfWeek = datepart(dw, GetDate())
SET @EndOfPrevWeek = DATEADD(dd, -@TodayDayOfWeek, GetDate())
SET @StartOfPrevWeek = DATEADD(dd, -(@TodayDayOfWeek+6), GetDate())

SELECT 
--- Тут выборка
WHERE
    CREATED_DATE BETWEEN 
 CONVERT(DATE, @StartOfPrevWeek,7)
AND
 CONVERT(DATE, @EndOfPrevWeek+2,7)
GROUP BY
 p.PRODUCT_NAME 

Если воскресенье учитывать не надо – вместо @EndOfPrevWeek + 2 надо писать @EndOfPrevWeek + 1.

Сделать выборку по месяцу намного проще:

DECLARE @EndOfPeriod DateTime
DECLARE @StartOfPriod DateTime

SET @StartOfPriod = DATEADD(mm, DATEDIFF(mm,0,getdate())-1, 0)
SET @EndOfPeriod = DATEADD(mm, 1, @StartOfPriod)

SELECT
---- тут выборка
WHERE
 CREATED_DATE BETWEEN
 CONVERT(DATE, @StartOfPriod,7)
AND
 CONVERT(DATE, @EndOfPeriod,7)

Аналогичные штуки проходят с днём и годом.

Работает в т.ч. в MS SQL 2005 (если MSDN не врёт).

Хуже, будет ещё хуже!

За что можно любить Мэддисона? За то, что он честно показывает, как не надо делать игры.

Поэтому самые лучшие его обзоры – это обзоры всевозможного трэша вроде “Гульмэна” или адских псевдоэротических квестов. Смотришь и радуешься, что это происходит не с тобой. А под влиянием общего безумия у обозревателя порой рождаются остроумные шутки.

Кому-то кажется, что народно-подзаборней Мэддисона обозревать невозможно и что он дошёл до предела простоты – блуждает по игровым тупикам и закоулкам, а потом называет это “обзором”. И что хуже уже не будет.

На самом деле, хуже уже есть – это Let’s play-и. И сам Мэддисон их ненавидит. Когда просто играют и комментируют, то не выдерживает даже Мэддисон.

Видимо, видео в Интернете постигнет та же судьба, что тексты и фотографию. Оно будет всё больше обесцениваться.

среда, 19 сентября 2012 г.

Georges Simenon – Le Chien jaune

Смысл некоторых страниц пока выглядит довольно мутным. Но я всё равно героически дошёл до конца и узнал, кто убийца.

Прочитал вот это издание:

Сам автор утверждает, что романы, вроде этого, он писал за 3 дня. Что ж, 3 дня “Жёлтого пса” оказались просто превосходными. Экранизировали книгу почти сразу, а в наши дни она читается ничуть не хуже, чем в 1931.

Так и появляется неожиданная классика жанра.

Jens Köhn – Die Etruskier. Kinder des Tunia

Ещё одна книга из серии “Alte Kulturen am Mittelmeer” – как и предыдущие про критян и микенцев. Книжки про финикийкев в магазине уже не было – только эти три.

Издана в 1991, ещё до орфографической реформы. Единственный серьёзный недостаток – на странице 4 в качестве примера этрусской письменности изображена лемносская стела, которую всё-таки относят к пеласгам или тирсенам.

понедельник, 17 сентября 2012 г.

Не обижаясь на Северную Нигерию

Брин как-то назвал Россию Северной Нигерией. Многие обиделись, но мало кто заметил, что за этими словами нет ни опыта, ни внятных рассуждений. Похоже, это просто вера, и он верит в неё только потому, что в неё верили его родители.

Конечно, явление редкое. Но оно ничуть не удивительней, чем правоверный католик или ортодоксальный иудей, который работает биологом или астрофизиком.

Да, у умных и знаменитых людей бывают странные убеждения. Достаточно почитать в ЖЖ дневники практикующих программистов, чтобы понять: общение с машиной не улучшает понимание людей.

Удивляться таким заявлениям – всё равно что недоумевать, как современный учёный может верить во Всемирный Потоп и Теорию Разумного Творения. Вполне может, и это даже не будет вредить его карьере.

В книге Смаллиана, про которую я писал, есть хороший пример на эту тему. Если учёного загипнотизировать, он будет подчиняться приказам гипнотизёра. А религиозное воспитание в детстве – чем не гипноз?

Р. Смаллиан – Молчаливое Дао

Смаллиан – это такой Станислав Лем, только от математики. Советские дети помнят его по незабываемой “Как же называется эта книга?”. А ещё была “Алиса в Стране Смекалки” (“Королева думает, что Король думает, что Королева думает, что Король думает, что Королева не в своем уме…”).

Востоковеды этой книгой будут, пожалуй, недовольны. Ведь Смаллиан произвольно смешивает самые разные традиции в трактовке Дао! И это в то время, когда сами исследователи не уверены, читал ли Чжуан-цзы книгу Лао-цзы, несмотря на принадлежность к общей традиции. Дао – оно очень разное. У Лао-цзы – это “утроба”, из которой течёт всё сущее (т.е., женщина), у Чжуан-дзы – Великий Мастер, Кузнец, который отливает в своём горниле все предметы мира (т.е., мужчина, а утроба – не больше, чем его инструмент), а у конфуцианцев – “приоритетное направление” (“нет дорог, есть но направления”). Неужели он их не различает?

Я думаю, как раз для этой книги такое разделение и не важно. Смаллиан не исследует даосим. Он пытается найти там термины и рассуждения, чтобы объяснить явления, для которых ему не хватает слов европейской традиции. Примерно как Джек Лондон обнаруживал в монологе Чжуан-цзы про бабочку Белую Логику алкоголика. Или как я сейчас смотрю на перевод “Джона, Ячменное Зерно” и не могу найти главу, в которой приводится эта цитата – хотя точно помню, что она там была.

Не следует осуждать битников за то, что они заимствовали “неправильный” дзен-буддизм. Как будто в Японию буддизм приходил “правильным”! Даже христианство мутирует, превращаясь в надстройку над местными поверьями. Что уж говорить о методе. В самой Японии, судя по “Золотому Храму”, 90% дзена – не больше, чем музейные экспонаты.

Не страшно узнать даосизме из “Дао Винни-Пуха”. Страшно думать, что это лучшая книга по теме.

CSS: @import

Оказывается, в CSS можно делать include. Синтаксис вот такой:
@import url("filename") [type]
Типы бывают:
  • all - Все типы. Это значение используется по умолчанию.
  • aural - Речевые синтезаторы, а также программы для воспроизведения текста вслух. Сюда, например, можно отнести речевые браузеры.
  • braille - Устройства, основанные на системе Брайля, которые предназначены для слепых людей.
  • handheld - Наладонные компьютеры и аналогичные им аппараты.
  • print - Печатающие устройства вроде принтера.
  • projection - Проектор.
  • screen - Экран монитора.
  • tv - Телевизор.

Часто ли вы видите CSS-вёрстку на экране телевизора? Жалко, что там их не применяют. Можно бы было вырезать рекламные паузы через ADBlock.

С мест сообщают, что мобильные браузеры не понимают @import, если путь файлу не обрамлён url. Хотя по стандарту:

Работающий вариант:

@import url("filename") [type]
И не работающий:

@import "filename" [type]
эквивалентны.

И ещё – IE 7 не поддерживает типы. Более того, если указать тип, то он перестаёт подгружать и сам файл.

воскресенье, 16 сентября 2012 г.

showModalDialog’s returnValue is undefined in Chrome

С мест сообщают – в Chrome у showModalDialog returnValue – undefined. Баг известен с 2010 года и пока (16 сентября 2012) не исправлен.

Фиксить так:

В окне, которое вызывает модальное:

window.returnValue = undefined;
var result = window.showModalDialog("modalwindow.aspx", window, "dialogHeight:650px; dialogWidth:900px;");
if (result == undefined)
   result = window.returnValue;
if (result != null && result != "undefined")
  // Do something with the return value
  // defined in "result"

В модальном окне:

if (window.opener) {
    window.opener.returnValue = "your return value";
}
window.returnValue = "your return value";
self.close();

IE isn’t focusing anchor link

В IE обнаружен загадочный баг.

Если ASP.Net страница:

  • делает (например, по нажатию на страницу) redirect на другую через anchor (т.е. otherPage.aspx#anchor)
  • в IIS настроен ISAPI_Rewrite (локально повторить не удалось)
  • браузер – IE (повторяется в т.ч. в 9-ом)

То может случится так, что anchor “отбросится” и страниця загрузится как otherPage.aspx.

Выловить и перенастроить практически невозможно.

Единственный выход – вместо redirect вставлять в literal на странице “<script language=’javascript’>location.href = ‘otherPage.aspx#anchor’;</script>”. Можно дополнительно поставить проверку – делать такой redirect только если браузер ie. Название браузера искать в Request.Browser.Type.

О document.ready заботаться не стоит – redirect он и есть redirect.

пятница, 31 августа 2012 г.

Негодование

Спокойно, как Будда, реагировать на внешние раздражители – это кажется очень простым.

Просто берёшь, и зарекаешься “оспаривать глупца”. Задаёшь себе вопрос, есть ли тебе дело до чужой глупости и оставляешь её без ответа. И, чтобы успокоиться, спрашиваешь себя – неужели так важно, чтобы в мире исчезли все, кто думает ерунду? Разве не больше вреда от тех, кто глупости делает? Стоит ли так забрасывать камнями то, что уже давно само себе памятник?

А если идея не глупая, а вредная? Например, кто-то собирается взять власть и начать всех вешать? Тут важно напомнить себе, что человек, который собирается взять власть, а потом вешать, никогда не будет говорить об этом вслух, называя конкретные имена. Он сначала возьмёт власть – и только потом вешать будет. Иначе он рискует до этого дня попросту не дожить – ведь потенциальные висельники тоже смотрят новости и читают блоги.

Некоторые неопытные йоги думают, что чтобы успокоиться – достаточно “откинуть негативные эмоции пустяковым поводам”. Но это не помогает. Потому что “негативные эмоции” – не единственная, и даже не главная дверь, через которую беспокойство лезет в наш мир. Её слишком просто закрыть.

Куда больше волнений лезет через “приятные” эмоции, которые мы и не думаем ограничивать. Что поделать – любит человек поучать, издеваться ир демонстрировать образованность. И именно эти чувства даже не раскачивают, а просто носят нас, как шлюпку в шторм.

К тому же, агрессия в ответ на глупость – это естественно и полезно. Нам нужно как-то “отбросить” вредоносных тараканов, которые полезли из чужой головы. Тут же срабатывает что-то внутри (на уровне инстинктов, я думаю). И кричит: “Брось каку!”

А ещё человеку нравятся диковины чужих глупостей. Множество сайтов и блогов попросту коллекционируют чужие маразмы, а людей, которые прославились своей глупостью, куда больше чем тех, кого бы прославил ум. Каждый дурацкий текст очередного сумасшедшего так и просится, чтобы мы переслали его друзьям. Так было и до Интернета – монолог “про гастроном на улице Герцена” знали лучше, чем всю остальную медицинскую энциклопедию.  А ещё раньше были Фома и Ерёма, всероссийские недотёпы.

Так что эти двери просто так не закроешь. Одну запрёшь – а незваные гости уже врываются во вторую, и вот уже обе опять нараспашку.

Что делать?

Увещеваниями здесь не поможешь. Хоть и написал Сенека De Ira, люди гневаются, как и раньше. Остаётся народное средство – честно проговаривать свои эмоции.

Например, комментарий от профана. Прежде, чем отвечать, прислушайтесь к себе (не беспокойтесь, комментарий никуда не убежит). И скажите честно – “я в гневе на этого дурака”. Или “я рад, что умнее этого дурака”. Или – “меня восхитила маразматичность этого дурака”.

И уже не будет нужды отвечать или спорить. Вместо фильма, в котором что-то надо делать, мы стоим перед картиной. Можно посмотреть, можно удивиться – но потом всё равно идёшь дальше.

Двери не заперты. Но незваные гости не заходят дальше порога.

среда, 29 августа 2012 г.

Дж. Х. Рейнвотер – Как пасти котов

Книга об управлении программистами. Большинство советов либо слишком абстрактны, либо слишком мелочны чтобы их можно было запомнить. Начинается бодренько, а потом разочаровывает всё – даже немногочисленные коты на буквицах.

Где-то в книге скрывалась история о том, как проектный менеджер Джон завалил проект, потому что даже не пытался понять, что там происходит. Я так и не смог её разыскать. Видимо, она была не очень связана с той главой, в которую её поместили.

Зато я нашёл другую хорошую цитату и выписываю её отдельно, потому что она мне очень понравилась.


Поймите, других людей вам не исправить. Это очевидное, на первый вгляд, обстоятельство очень помогает в процессе взаимодействия с окружающими.

Возможно, ради неё и стоило читать всю книгу

воскресенье, 26 августа 2012 г.

Фриланс и не фриланс

Не следует путать фриланс и удалённую работу.

Фриланс – вы находите заказчика и делаете ему разовую работу. А потом ищите другого заказчика.

Удалённая работа – вы числитесь в штате, но часто работаете из дома, а не из офиса.

Разумеется, удалённая работа – это хорошо. А фриланс – нет.

Достаточно сравнить, сколько денег платят за то, и за это.

суббота, 25 августа 2012 г.

Click() doesn’t work in Chrome and Safari

Иногда нужно сделать, чтобы файл загружался не через форму по умолчанию (которая отличается у разных браузеров), а по нажатию на кнопку. Форму прячут, вместо неё ставят кнопку и вызывают по щелчку для неё click() для спрятанной формы.

Как правило, это работает. Но в браузерах на движке WebKit (например, Chrome и Safari) может и не сработать. В частности, Safari игнорирует click() по скрытым объектам.

Поэтому надо скрывать “народным” способом, чтобы не поломать вёрстку:

Вместо:

display: none;

Поставить в CSS:

width: 0px;
height: 0px;
position: absolute;

четверг, 23 августа 2012 г.

Универсальный совет

Пожалуйста, не делайте личные проекты, сайты и блоги на сложных (особенно самописных) платформах.

Вы рискуете так никогда их до конца и не настроить.

понедельник, 13 августа 2012 г.

Дэвид Аллен – Как привести дела в порядок

Это замечательная книга. Никаких общих советов, рассуждений обо всём и заумных йогически-психоаналитических терминов. Человек описал во всех тонкостях (вплоть до цвета папок) ту систему, которой пользуется сам. Она совершенно не похожа на поразившую меня в своё время систему Любищева, но задачу свою выполняет.

У системы Любищева есть миллион достоинств и даже известный популяризатор, но есть у неё и недостатки. Самый главный (который, всегда по-своему, есть у каждой подобной системы): она подходит только людям склада Любищева. Точно так же и советы Аллена очень хорошо подходят Аллену – и мне тоже.

Разумеется, заводить папки (расписыванию которых посвящены первые главы) будет нужно, если вы работаете большим начальником. Но другие советы работают и без папок.

Если вам не помог ни Аллен, ни Любищев, можно поискать и других авторитетов. В конце концов, рано или поздно любой человек нащупает организацию труда, которая подходит под его темперамент и всё, что он читал раньше, найдёт у него своё место.

Есть, правда, ещё одна штука, которая не даёт нам ни нормально работать, ни нормально организовать работу.

Любая система управления задачами и рабочим временем работает на искренности, как мотоцикл на бензине. Чтобы поручить ей свои дела, нужно их перечислить. Не каждый готов, подобно Монтеню или Дюреру, изобразить себя без штанов (даже если смотреть будет только он сам). Если раздеться перед зеркалом, мы видим выдавшийся живот, впалую грудь, подмышки, которые хотят бритвы и то, что мы не отнюдь не годимся для модельного бизнеса. А взглянув на свои дела, мы убеждаемся, что мы не Стив Джобс, и даже не Дональд Трамп.

Нам остаётся только набраться мужества, заняться физкультуркой и хотя бы раз в жизни честно признаться себе в том, чего мы хотим и что мы делаем. Если делать это регулярно, зеркало перестаёт нас пугать.

Вообще, про Любищева надо будет написать подробно.

Группа и её фокусы

Те, кто “вокруг” – это наша фокус-группа. Люди, чьё мнение мы слышим.

Прочие – посторонние, они могут говорить что угодно.

“Вокруг одни идиоты” обычно значит, что человек считает идиотами свою фокус-группу. И сообщает им это в лицо. Поэтому если вы посторонний – спорить с ним не нужно. Он не вам говорит и не вас имеет в виду.

Интернет сблизил и перемешал фокус-группы и их обитателей. Всё чаще люди видят слова, которые к ним не относятся. А потом на них ещё и обижаются.

Это так же глупо, как если бы английская королева обиделась на “God Save The Queen” от Sex Pistols.

Как защищаться?

Во-первых, подумать, а кто действительно входит в вашу фокус-группу? Чьих ответов мы ждём, чьи слова мы слышим?

Например, если начать кого-нибудь троллить – он тоже окажется в фокус-группе. Ведь мы ждём его ответов (даже если хотим просто поиздеваться).

Во-вторых, надо включить туда побольше умных людей. Так много, чтобы за самого себя стыдно стало. С тех пор, как в моей фокус-группе завелись Герб Саттер & Co, я и сам поумнел.

В-третьих, смело вычеркнуть оттуда тех, кому нельзя поручить даже покупку коробка спичек. Да, человек любит расширять свою фокус-группу, иногда до пределов вселенной. Он от этого сам себе кажется больше. Хотя в жизни даже фокус-группа размером в страну обычно бесполезна (если вы не собираетесь выиграть президентские выборы).

Любой невежда, которые говорит что-то, с чем мы не согласны,  так и просится, чтобы мы втащили его в свою фокус-группу и там хорошенько унизили. Словно колючки, которые цепляются за одежду. Дискуссия невежд, которых надо просвещать и разговор дураков, над которым мы смеёмся, отличаются обычно только тем, можем ли мы принять в них участие.

Немудрено: всё, что мы комментируем, кажется ужасно значительным.

вторник, 7 августа 2012 г.

Christian Bieniek – Karla mit großen Klappe

История про девочку, которая вдруг решила говорить только правду. Довольно неплохая, но мне не понравилась. Слишком много семейных скандалов.

И что-то не верится, что неугомонная Карла говорила неприятную правду просто в качестве эксперимента. По-моему, она просто вредина.

Но всё равно приятно читать про Грёнланд и наблюдать живую немецкую речь.

Книжка нашлась в Институте Гёте, раздел детской литературы.

суббота, 30 июня 2012 г.

Detlef Rössler – Mykene. Burg des Agamemnon

Книга из той же серии, что упомянутая раньше Kreta. Insel des Minos. Идём хронологически – сначала критяне, потом завоевавшие их минойцы, а дальше будут этруски из той же серии.
Скроена по тому же принципу, что предыдущая:

  1. Как раскопали
  2. Как жили цари
  3. Как велось хозяйство
  4. Как жил народ
  5. Каким богам поклонялись
  6. Как пришли завоеватели (в случае критян – минойцы, в случае минойцев – дорийцы) и всех завоевали

Sitecore: Database returns old value

Вы исправили какие-то данные в базе Sitecore, но на странице у вас то же самое? Значит, надо проверить следующие варианты:

  1. Вы исправили в master, но забыли опубликовать это в web. Перейдите в web и провериться.
  2. Вы изменили не во всех языках. Вернитесь в master и проверьте, выбрав другой флаг. Этот шаг очень часто забывают.
  3. Вы используете дурацкую систему кэширования и она возвращает вам старые значения.
Чтобы 1 и 2 портили вам как можно меньше крови - везде, где можно, заменяйте текстовые константы на внутренние ссылки sitecore. И тогда даже если элемент куда-нибудь переедет,  ссылка будет в порядке.

четверг, 28 июня 2012 г.

Tool: Notepad++ vs KomodoEdit

What is better - Notepad++ or Komodo Edit? I have been used Notepad++ for a long time, but what if the cross-platform Komodo Edit is better?

 I've downloaded and used for 60 days with Windows 7.

My verdict is: Komodo Edit has all of the pluses that Notepad++ has.

But there's 2 minuses of Komodo Edit:
  • It is loaded slowly. Cross-platform libraries aren't the fastest.
  • It isn't useful for modern Russian charsets. If you will make an HTML page with it, Safari will show you just ??????
So, I'm on Notepad++ still. But of course there aren't any Notepad++ for Unix.

Blog: Wordpress?

Работа над Yume Hikki идёт полным ходом. А значит, время подыскивать хостинг. Всё-таки это не эмулятор Радио-86 и raw-view с Google Code будет для него слишком медленным.


Blogspot не перестаёт радовать дизайном, удобством и стильностью. Но здесь только 10 статичных страниц и нет FTP-доступа.

Joomla для личного сайта вообще не годится. Её невозможно настроить двумя кликами.

А с Wordpress-ом у меня страшные ассоциации. На нём было сделано слишком много страшных, уродливых, совершенно неработоспособных сайтов. Поэтому уже первый взгляд на круглые кнопки его админки вселяет в меня ужас.

Выход один - преодолеть предубеждение. И пусть меня осудят на Луркморе, - но в умелых руках Wordpress будет слушаться. Ведь пользуется им Herb Sutter - а этот человек разбирается в надёжности.

Блогспот, в свою очередь, может похвастаться тем, что там одно время писал Линус Торвальдс. Записей маловато, зато можно заглянуть за плечо известному человеку:


 И сравнить с работой совсем другого человека (тоже IT):

Мне надоело подписывать договоры и платежки, решать хозяйственные вопросы, отвечать на полтораста электронных писем в день, 99% вопросов в которых находятся не в моей компетенции. В последние годы каждый вечер по 6 часов я работал почтальоном по переадресации писем, звонков и личных обращений, адресованных другим сотрудникам компании. В последние годы с ростом бизнеса моя почта приняла характер эпидемии, поэтому с сегодняшнего дня я отказываюсь и от своего корпоративного электронного почтового ящика – его будет проверять мой преемник.

среда, 20 июня 2012 г.

JavaScript: keydown event in Opera

Я уже писал про сайт-бродилку. Легко заметить, что в Opera он работает неправильно - если зажать стрелку, то главный герой сместится только на один шаг.

Почему так происходит? Можно ли это исправить?

Эксперименты показали, что если зажать кнопку со стрелкой, то Opera отловить как keydown только сам момент нажатия. Пока не отпустишь кнопку - события в JavaScript происходить не будет, оно будет перенаправлятсья на Scroll Bar.

Так что из Opera можно бродить только шаг за шагом. И отладчик в ней вызывается не как у людей.

Tool: Development tool

  • Firefox - Firebug - F12
  • Chrome - Included - F12
  • Safari - Included - F12
  • Internet Explorer - Included - F12
  • Opera - Dragonfly (now is included) - Ctrl+Shift+I (!!!)
 I don't know why.

понедельник, 18 июня 2012 г.

Cygwin: Делаем немыслимые вещи

Немыслимо интересные вещи на bash (кое-что и на Cygwin неплохо работает). На случай, если сайт слетит (Web 1.0, что поделать) - сохраните у себя.

Перепостил бы целиком, но Linux-ом пока не пользуюсь.

C#: Labels instead of numbers in String.Format

Can be labels used instead of numbers in String.Format?

No, they aren't by default. But it's possible by the very nice Scott Hanselman's extention method for it:

public static class FormattableObject
{
    public static string ToString(this object anObject, string aFormat)
    {
        return FormattableObject.ToString(anObject, aFormat, null);
    }
 
    public static string ToString(this object anObject, string aFormat, IFormatProvider formatProvider)
  {
       StringBuilder sb = new StringBuilder();
     Type type = anObject.GetType();
     Regex reg = new Regex(@"({)([^}]+)(})",RegexOptions.IgnoreCase);
        MatchCollection mc = reg.Matches(aFormat);
      int startIndex = 0;
     foreach(Match m in mc)
      {
           Group g = m.Groups[2]; //it's second in the match between { and }
           int length = g.Index - startIndex -1;
           sb.Append(aFormat.Substring(startIndex,length));
             
            string toGet = String.Empty;
            string toFormat = String.Empty;
         int formatIndex = g.Value.IndexOf(":"); //formatting would be to the right of a :
           if (formatIndex == -1) //no formatting, no worries
          {
               toGet = g.Value;
            }
           else //pickup the formatting
            {
               toGet = g.Value.Substring(0,formatIndex);
               toFormat = g.Value.Substring(formatIndex+1);
            }
 
           //first try properties
          PropertyInfo retrievedProperty = type.GetProperty(toGet);
           Type retrievedType = null;
          object retrievedObject = null;
          if(retrievedProperty != null)
           {
               retrievedType = retrievedProperty.PropertyType;
             retrievedObject  = retrievedProperty.GetValue(anObject,null);
           }
           else //try fields
           {
               FieldInfo retrievedField = type.GetField(toGet);
                if (retrievedField != null)
             {
                   retrievedType = retrievedField.FieldType;
                   retrievedObject = retrievedField.GetValue(anObject);
                }
           }
 
           if (retrievedType != null ) //Cool, we found something
          {
               string result = String.Empty;
               if(toFormat == String.Empty) //no format info
               {
                   result = retrievedType.InvokeMember("ToString",
                     BindingFlags.Public | BindingFlags.NonPublic |
                     BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.IgnoreCase
                     ,null,retrievedObject,null) as string;
              }
               else //format info
              {
                   result = retrievedType.InvokeMember("ToString",
                     BindingFlags.Public | BindingFlags.NonPublic |
                     BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.IgnoreCase
                     ,null,retrievedObject,new object[]{toFormat,formatProvider}) as string;
             }
               sb.Append(result);
          }
           else //didn't find a property with that name, so be gracious and put it back
            {
               sb.Append("{");
             sb.Append(g.Value);
             sb.Append("}");
         }
           startIndex = g.Index + g.Length +1 ;
        }
       if (startIndex < aFormat.Length) //include the rest (end) of the string
      {
           sb.Append(aFormat.Substring(startIndex));
       }
       return sb.ToString();
   }
}

It's faster then others. Use it with objects:
Person p = new Person();
string foo = p.ToString("{Money:C} {LastName}, {ScottName} {BirthDate}");

воскресенье, 17 июня 2012 г.

Blog: Chrome says, that vising the blog may harm your computer

Что делать, если Гугл говорит, что ваш сайт опасен, а в коде и плагинах появились загадочные и явно зашифрованные куски? И то тут, то там находишь зловещий eval(base64_decode.

Правильный ответ - грохнуть всё и восстановить из backup-а.

Если пытаешься убрать руками:

  • Никаких гарантий, что убрал всё
  • Рискуешь что-то поломать
  • Потратишь много времени - намного больше, чем уйдёт, если заливать те же статьи снова.

пятница, 15 июня 2012 г.

jQuery: "name.replace is not a function" error

It's a very widely known error, since jQuery 1.0 probably. I'll describe he solution en English, because there aren't any English manual for it too.

If you implement the OOP inheritance in JavaScript using this very famous code:

Object.prototype.Inherits = function(parent)
{
 if(arguments.length > 1)
  parent.apply(this, Array.prototype.slice.call(arguments,1));
 else
  parent.call(this);
}

Function.prototype.Inherits = function(parent)
{
 this.prototype = new parent();
 this.prototype.constructor = this;
}

fadeIn() and fadeOut() will cause this error :-(.

Anyway, this version of inheritance isn't so good at all, because it breaks JavaScript foreach-like for too, adding 1 more element "Inherits" to every array.

But what if you have to use it? Is there any way to fix?

Firstly, update this implementation to make it safe:

Object.prototype.Inherits = function(parent)
{
 if(!parent || typeof(parent.call) != "function")
  return;
 if(arguments.length > 1)
  parent.apply(this, Array.prototype.slice.call(arguments,1));
 else
  parent.call(this);
}

Function.prototype.Inherits = function(parent)
{
 this.prototype = new parent();
 this.prototype.constructor = this;
}

Then update jQuery.js (is you have a min version, replace it with full one). Find "getComputedStyle = function( elem, name ) {" and add after first 2 lines:

getComputedStyle = function( elem, name ) {
 var ret, defaultView, computedStyle, width,
  style = elem.style;
 //Add this:
 if(typeof(name) != "string")
  return name;
 //-----

And it will work fine :-)

среда, 13 июня 2012 г.

JavaScript: Receiving GET params of url

Как прочитать в JavaScript параметры, которые идут в URL сразу после ? и имеют вид key=value?

Внимательно вчитаться в образец и сделать ещё удобней:

$.extend({
 getUrlVars: function(){
  var vars = [], hash;
  var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
  var hashesLength = hashes.length;
  var i = 0
  while(i < hashesLength)
  {
   hash = hashes[i].split('=');
   vars.push(hash[0]);
   vars[hash[0]] = hash[1];
   i++;
  }
  return vars;
 },
 UrlVars : null,
 getUrlVar : function(key) {
  if(!key)
   return null;
  if(!this.UrlVars)
   this.UrlVars = this.getUrlVars();
  if(typeof(this.UrlVars[key]) == "undefined")
   return null;
  else
   return this.UrlVars[key];
 }
});

И теперь в любом месте вызываем $.getUrlVar('key') и получаем этот параметр. Если параметра не было - вернёт null.

вторник, 12 июня 2012 г.

Life: Программист с Кубы

David Conde, программист из Матансаса, Куба.

При этом - Куба, Иран, Сирия, Северная Корея и Судан (после последнего референдума неясно, весь, или только Северный) не имеют доступа к Sourceforge.

UnitTest: Что такое UnitTest?


Unit в UnitTest - это unit of work. То есть a use case, вызванный public method-ом и закончившийся result-ом. А result-ом может быть:
  1. Возвращаемое значение или Exception.
  2. Заметные изменения в системе. Заметные - значит, система после них работает по-другому. Например, добавление пользователя - это заметное изменение, потому что теперь под ним можно заходить.
  3. Вызов внешней системы, которую мы не можем контролировать во время теста. Например, файловая система, сеть, user threads, или любая другая зависимость, которую мы не можем контролировать и которая выполняется медленно.
Для 3-его типа нужно использовать mock-объекты. Для 1-2 - порвать все зависимости и проверять возвращаемое значение или состояние системы.

Вроде бы просто. Тем не менее, я понял, что отчего-то был уверен, что UnitTest-у и случая 1 достаточно. Хотя уже созданы обёртки для эмуляции файловой системы. Или вот эксперименты над Python

Subversion: How to use SVN with Google code

Как использовать SVN в Google Code? Вроде бы всё очень просто, но всё равно постоянно забываешь. Поэтому переведём замечательный мануал по настройке.

Более поздняя версия статьи публиковалась на Standalone автора. Standalone давно умер, а блог на wordpress жив до сих пор

Помечаю в основном для себя, так что картинок не будет.

Если нужно просто утащить последний release чужого проекта, а пароля вы не знаете - достаточно выполнить пункты 1-4, а потом регулярно делать Update. Google Code даёт read-only доступ всем желающим.

  1. Скачиваем последний TortoiseSVN.
  2. Устанавливаем его и перезагружаемся.
  3. Создаём папку, щёлкаем по ней правой кнопкой, жмём SVN Checkout.
  4. URL of repository = https://[ProjectName].googlecode.com/svn/trunk, где [ProjectName] - имя нужного проекта. Если вы его забыли, посмотрите URL его профиля на Google Code - он будет иметь вид http://code.google.com/p/[ProjectName]/.
  5. Идём в профиль нашего Google Code Hosting и смотрим там пароль.
  6. Потом, когда будем делать Commit, у нас спросят имя и пароль. Вводим то, что нам показали на шаге 5.
SVN ещё долго не умрёт - ведь он прост, как грабли.

Blog: Оптимальный формат

Оптимальный формат программистского блога очень хорошо формулирует английское слово papers. Т.е., наброски по какому-то вопросу, выложенные в сеть, чтобы не потерялись.

Нечто наподобие научных заявок на статьи. За некоторые из научных papers даже дают миллион - например, за известный paper Григория Перельмана.

суббота, 9 июня 2012 г.

Script: Play mp3 at background with JavaScript

Как сделать фоновую мелодию для веб-страницы из mp3-файла?

Для начала - убедиться, что она нужна. Я, например, считаю, что единственное место во всём Вебе, где уместны фоновые мелодии - это игры. Пожалуйста, ставьте такие скрипты только в них.

Так как стандарт очень долго хранил молчание насчёт фоновых мелодий, каждый браузер реализовывал его по-своему

Путаница тут страшная. <embed>, который часто советуют, например, требует от Firefox подгружать плагин. <audio> толком не поддерживается даже в IE. Да и вообще, ещё 2 года назад разные браузеры поддерживали разные форматы и табличка выглядела приблизительно так:

Browser Ogg MP3 WAV
FireFox 3.6+
Safari 5+
Chrome 6
Opera 10.5+
Internet Explorer 9 (beta)

Так что используйте JPlayer. Но иногда и он обваливается с ошибкой, что b.test - не является функцией :(.

Мне jPlayer не помог. Пришлось родить кроссплатформенное решение:

<bgsound src="sound/plan.mp3" loop="1">
<object id="opera_player1" data="sound/plan.mp3" type="application/x-mplayer2" width="0" height="0">
 <param name="filename" value="sound/plan.mp3">
 <param name="autostart" value="1">
 <param name="autoplay" value="1">
 <param name="hidden" value="1">
 <param name="playcount" value="9999">
</object>
<audio src="sound/plan.mp3" autoplay="autoplay" loop="loop">
<object id="webkit_player" data="sound/plan.mp3" type="application/x-mplayer2" width="0" height="0">
 <param name="filename" value="sound/plan.mp3">
 <param name="autostart" value="1">
 <param name="autoplay" value="1">
 <param name="hidden" value="1">>
</object>
</audio>

В IE я это, впрочем, пока не тестировал.

Первый блок - исключительно для Opera. Во втором не забываем loop="loop" - Chrome игнорирует Playcount.

Важно помнить, что object в Firefox не понимает loop. Так что просто ставьте большой playcount. А вот webkit-браузеры понимают его слишком хорошо и будут играть мелодию, даже когда вы покините сайт. Поэтому не забудьте убрать param loop во втором блоке.

И никогда не пытайтесь сгенерировать этот код через JavaScript. Такая реализация страшно тормозит даже на локальном компьютере.

А ещё не забывайте, что браузеры - умные создания и если поместить эти object'ы в скрытый блок (не важно, через, display: none; или visibility: hidden), Firefox их проигрывать не будет.

Причём мы говорим, разумеется, о desktop-ных браузерах. Про мобильные даже вспоминать страшно.

пятница, 8 июня 2012 г.

C++: Счастливый билет с длинной арифметикой

Счастливый трамвайный билет - это такой, у которого сумма первых трёх цифр номера равна сумме трёх последних. При встрече его полагается съесть.

Сколько таких билетов всего? Какова вероятность встретить счастливый?

Алгоритм для этих вычислений в Википедии настолько ужасен, что народ с Хабра довольно быстро породил в комментариях огромное количество вариантов на C++, Perl и... SQL.

Я тоже не смог пройти мимо и написал считалку на C++ с арифметикой указателей и поддержкой длинной арифметики. При желании она может считать хоть 12-значные числа.

Оптимизировал всем, о чём пишут в пособиях для начинающих. Получилась миниатюрная машина Тьюринга, которая бегает указателем по числам и считает разряды:

void inline count_lucky(unsigned int num_length_val)
{
  bool is_odd = (num_length_val % 2) > 0;
  unsigned int num_length = (is_odd) ? num_length_val - 1 : num_length_val;
  register unsigned int lucky=1, total=pow(10.0,(int)num_length), i;
  char *num = new char[num_length], *end=num+(num_length-1);
  register char *pos=end;
  for(i=0; i < num_length; i++)
    num[i]=0;
  while(pos>=num)
  {
     if((*pos)<9)
     {
        (*pos)++;
        if(pos==end)
        {
           if(is_lucky((unsigned char*)num, num_length))
             lucky++;
        }
        else
          pos++;
     }
     else
     {
       *pos=-1;
       pos--;
     }
  }
  printf("Lucky are %d of %d (%.3f%%)\n",(is_odd) ? lucky * 10 : lucky, (is_odd) ? total * 10 : total,((float)lucky/total*100));
  delete[] num;
}
bool inline is_lucky(unsigned char* items, unsigned int items_count)
{
  unsigned char val1=0, val2=0;
  unsigned int half = items_count >> 1;
  for(unsigned int i=0; i < half; i++)
  {
    val1 += items[i];
    val2 += items[items_count-1-i];
  }
  return (val1==val2);
}
Увы! Как показывает практика, уже на 7-значном билете тупой перебор, развёрнутый и оптимизированный компилятором, оказывается эффективней. Похоже, компилятор попросту выполняет сам большую часть явно заданных вычислений.
В этом легко убедиться, запустив тест хотя бы для 7 разрядов:

void inline count_lucky(unsigned int num_length);
bool inline is_lucky(unsigned char* items, unsigned int items_count);

int _tmain(int argc, _TCHAR* argv[])
{
  clock_t start = clock(), mine;
  count_lucky(7);
  mine=clock();
  printf("Mine time was: %d\n", (mine - start));
  count_lucky_fromwiki();
  printf("His time was: %d\n", (clock() - mine));
  return 0;
}

void count_lucky_fromwiki()
{
  int total=0,lucky=0;
  for(int i1=0; i1<10; i1++)
    for(int i2=0; i2<10; i2++)
      for(int i3=0; i3<10; i3++)
        for(int i4=0; i4<10; i4++)
          for(int i5=0; i5<10; i5++)
            for(int i6=0; i6<10; i6++)
              for(int i7=0; i7<10; i7++, total++)
                  if(i1+i2+i3 == i5+i6+i7)
                    lucky++;
  printf("Lucky are %d of %d (%.3f%%)\n",lucky,total,((float)lucky/total*100));
}

Человек уже не может обогнать машину :(. Слава роботам!

В качестве утешения - на 8 вложенный циклах валился компилятор из Borland C++ Builder 6.

Script: Replace in multiple files in Windows

A simple script to replace somethign in multiple files for Windows...

I've seen such a script for MS DOS Batch files. But I'd lost it and nobody could help me. I had ActivePerl, but the one-liner for replace in multiple files could be used only in *nix shell because of "/' things.

And finally I've got it for MS PowerShell. Here it is:

(Get-Content C:\Scripts\Test.txt)
| Foreach-Object {$_ -replace "\*", "@")
| Set-Content C:\Scripts\Test.txt

Thank you, Scripting Guy!

Phylosophy: ElseIf vs Switch, Python vs XSLT

There're ELSEIF operator in Python, and there aren't any SWITCH.

There're SWITCH operator in XSLT (aka <xsl:choose>), and there aren't any ELSEIF. There aren't any ELSE in it even.

C#: Difference between && and &

(I'll write in English, because this problem is widely asked.)

What's the difference between && and & or || and | in C#? In C++ it's the difference between logical and bitwise AND.

The most of its usage as connected with universality of if in C++. For example, if(a) in C++ never executes when:
  • a is false (because false = 0)
  • a is null (because null = 0)
  • a is a number <=0.

So, if(a == true) or  (a > 0) is useless in C++. if(a) is much shorter.


JavaScript implemented 1 more option:
  • a is an empty string ("")
C# is a strongly-typed langauge and the if in C# works different. It accepts only boolean values in scope.

So, the only difference between | an || and & and && in C# is the short-circuiting.

i.e.:


if(foo() && boo())


if foo() == false, boo() willn't be executed.


if(foo() & boo())


The foo() and boo() will be executed.


So, never write this way:


if(a != 0 & b / a > 100)


if a == 0, it will fall in Division by DivideByZeroException. The right variant is:


if(a != 0 && b / a > 100)

The same thing:

 if(item != null & item.isActive())

Never write this way. It has to be written like this:


 if(item != null && item.isActive())

среда, 6 июня 2012 г.

Book: Reinhard Witte - Kreta. Insel des Minos

Book: Reinhard Witte - Kreta. Insel des Minos (Der Kinderbuchvelag. Berlin. Illustrationen von Ludwig Winkler).


There're 2 more books from the same serie to read.

Subversion: GoogleCode против SVN

Очень мной любимый эмулятор Радио-86РК на JavaScript не нуждается даже в хостинге, чтобы работать. Проект, залитый через Mercurial, доступен для чтения всем, а значит, нет нужды заморачиваться с хостингом. Достаточно поставить ссылку напрямую в репозиторий.

Отличная идея! А что будет, если залить проект через SVN?

Увы - ничего хорошего. HTML-документ, загруженный через SVN, можно открыть из браузера... но сервер вернёт его как [text/plain], а не как [text/html]. И браузер покажет вместо страницы её исходный код.

К счастью, Google Code поддерживает репозитории 3 форматов: SVN, Git и Mercurial. Вот и выпал случай их протестировать.
  • SVN - работает неправильно
  • Git - работает правильно (TortoiseGit + msysgit, указать в настройках Tortoise c:\Program Files\Git\bin\ как источник git.exe). Лучше брать git.exe из официального git-scm.
  • Mercurial (он же Hg) - работает правильно
Google Code не любит SVN. Или SVN не любит Web.

Я решил пользоваться Mercurial. Почему?

Life: В полку Блогспота прибыло!

Не секрет, что социальная сеть становится социальной не потому, что там народу много, а потому, что там много наших знакомых. В этом прелесть ВКонтакте - только вышел, а там все свои. И это убивает LiveJournal - из 5-7 людей, которых с которыми я познакомился прежде, чем прочитал их блоги, сейчас активно пишет 1, а большинство поудалялось.

Сегодня на Blogspot-е пополнение - мой бывший одноклассник и просто хороший человек застолбил себе домен Venarg. Туда он будет перекидывать всё, что скопилось в "Черновиках" Гуглопочты. Да, в наше время тоже приходится писать на конвертах - нормального сервиса хранения заметок так и не придумано.

Так получилось, что в Рунете Блогспот стал логовом программистов и админов. Почему? Здесь странная френдлента, так что его читают люди, освоившие RSS и Google Reader. Здесь нет топа ЖЖ, а значит и не нужно LJPromo, чтобы накручивать посещаемость. Здесь пока нет ветвистых комментов, а значит, нормального срача не устроишь. Кандидаты в президенты и простые демократические журналисты не открывают здесь свои представительства. Тут даже ботов нет.

А люди - есть. И сегодня их стало на 1 человек больше.

Blog: Lexa Андреев о блоговодстве

В своё время очень не любил этого автора. Посмотрел недавно - вырос, существенно вырос.

Его статья о том, как перестать быть блоггером и начать жить - великолепна.

Reinhard Witte – Kreta. Insel des Minos

Книга про древних критян. Приятно, что авто не только пересказал все положенные легенды, но и хорошенько расписал порядок жизни царей и простых критян, включая их равзлечения и культуру.

Ввиду того, что интернета тогда не было, рапсод был таким же профессионалом, как кузнец или плотник. Поэтому народное творчество уже тогда творил не народ, а профессионалы. И вообще, профессия была уважаемая и доходная - другое дело, что и столетия спустя вполне себе подвижные арабы иной раз называли путешествие одной из тех мук, которые должны приготовить человека к жизни на том свете.

Интересно, что гомеровские цитаты я понимал легче, чем весь остальной текст.

вторник, 5 июня 2012 г.

Life: Couchsurfing

Итак, каучсёрфинг.

Самым лучшим считается Couchsurfing.org. Там расширенные профили, так что больше доверия. Ещё есть HospitalityClub и Global Freeloaders, они хуже.

Ещё есть сервис для эсперантистов.

Да, ещё - если вы не женщина, ваши шансы невелеки.


пятница, 25 мая 2012 г.

Life: Как сконвертировать djvu?

Как сконвертировать DJVU в PDF? Например, если нужно загрузить в читалку.

По старинке обычно рекомендуют мелкие утилитки. Хотя уже давно есть куча сайтов, которые конвертируют прямо в онлайне. Docspal, например.

вторник, 22 мая 2012 г.

Books: Паттерны, сэр!

Кто-то издаёт толстенные тома, в которых переводит стандартные паттерны из известной книжки на C#, Java, Python...

А кто-то новые печёт!

понедельник, 21 мая 2012 г.

Tools: Remove whitespaces at the end of lines in Visual Studio

Известный поисковый запрос, вынесенный в заголовок - одна из самых навязчивых проблем Visual Studio.

Опытные пользователи знают, что в поиске-замене есть свой RegExp. Но работает он не так, как у людей.

Что делать? Искать готовые решения.

Например:

:Zs#$ - все пробелы на конце строк
^:d+ - все цифры в начале строк (например, из какого-нибудь блога код скопировал)

Список будет пополняться.

пятница, 18 мая 2012 г.

Philosophy: Паттерны - 2

Wolfgang Pree из Зальцбурга тоже исследовал паттерны и написал про них книжку. В отличии от писаний "банды четырёх", в Рунете про неё почти никто не слышал.

Даже перевода нет.

Зато есть конспект на английском.

ASP.Net: Текущая страница из ASCX

Как узнать текущую страницу из ASCX? Например, для какой-нибудь компоненты из недр sitecore layout?

Вот так:

String.Format("{0}://{1}{2}",
                Request.ServerVariables["HTTPS"] == "on" ?
                    "https" :
                    "http",
                Request.ServerVariables["SERVER_NAME"],
                Request.RawUrl.ToString());

четверг, 17 мая 2012 г.

Script: Popup по центру экрана

Как поставить кнопки Facebook/Twitter/Google со своими иконками? Берём и ставим a с соответствующими href:

Twitter:
https://twitter.com/intent/tweet?url={PageUrl}&text={PageUrl}

Показываеть Twitter как blank - не надо. Если вставить сакральную мантру:

!function(d, s, id)
< script type="text/javascript" >
{ 
  var js, fjs = d.getElementsByTagName(s)[0];
  if (!d.getElementById(id))
  {
    js = d.createElement(s);
    js.id = id;
    js.src = "//platform.twitter.com/widgets.js";
    fjs.parentNode.insertBefore(js, fjs); 
 } 
} (document, "script", "twitter-wjs");
< /script >
< script type="text/javascript" src="//platform.twitter.com/widgets.js" >< /script >

 то он сам всё найдёт и откроет. Попытаешься повесить скрипт - начнёт показывать 2 окна.

Facebook:
http://www.facebook.com/sharer.php?t={PageTitle}&u={PageUrl}

По необъяснимой причине он не видит PageTitle, если запускать с локального сервера.

Google Share (не путать с Google +1!):
https://plus.google.com/share?url={PageUrl}

Pinterest:
http://pinterest.com/pin/create/button/?url={PageUrl}&media={PageImage}&description={PageTitle}

А открывать это надо через _blank и по центру экрана:

function PopupCenter(pageURL, title, w, h) {
   var left = (screen.width / 2) - (w / 2);
   var top = (screen.height / 2) - (h / 2);
   var targetWin = window.open(pageURL, title, 'menubar=no, toolbar=no, resizable=yes, scrollbars=yes, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left);
} 

Функцию для открывания окна взял у Нимы.

И ещё - если во втором параметре window.open будет пробел, Internet Explorer его не откроет. Такие дела.

Design: Иконки

Book: Достоевский - Игрок

Та самая книга, которую Достоевский надиктовал за 25 дней. Короче, чем "Село Степанчиково", "Неточка Незванова" и "Двойник", но длиннее, чем "Бедные люди". Чтобы усилить жанровую чересполосицу - это считается романом (а иногда и "Белые ночи" считают романом), в то время как "Вечный муж" (такого же размера) - рассказ.

Сложно сказать, насколько каторжной была работа: Достоевский диктовал с 12 до 4, т.е. 4 часа в день.

fb2-версия оказалась на купленном в воскресенье букридере. Вот и прочитал.

Очень достойно и захватывающе. Радует la baboulinka и впечатляет раздолбайство главного героя, который может выиграть деньги, но тратит их на парижское житьё пресловутой mademoiselle Blanche. Нету безысходного мрака и сырости, которым шибает нас из школьной программы, где "Белые ночи" и "Преступление и наказание". Просто срыв резьбы и падение, падение, падение.

Словом, Достоевский, конечно, велик. Несмотря на школьную программу.

суббота, 12 мая 2012 г.

Script: Привет из эры Web 1.0

Собрания всевозможных CMD, Perl и прочих скриптов на радость админам.

Включая совершенно немыслимый CMD-шник, который по датскому названию птицы выдаёт её латинское видовое название. Из Википедии, разумеется. Причём парсит Википедию... через JScript!

"Это невероятно".

четверг, 10 мая 2012 г.

среда, 9 мая 2012 г.

Book: Программист-прагматик - 2, гл. 3-8

17. Сохраняйте данные в виде простого текста. Так проще править руками

18. Графические интерфейсы:

преимущество - WYSIWYG - получаешь то, что видишь

недостаток - WYSIAWYG - получаешь только то, что видишь

Поэтому любите командную строку, а в ней - cygwin или даже UWin.

19. Используйте 1 редактор, но по максимуму. Требования: настраиваемость, расширяемость, программируемость

20. Отлаживать без паники. Не обвинять, а исправлять. Не предполагайте - доказывайте.

21. Добиться воспроизводимости, и только потом чинить. Метод “резинового утёнка”

22. Используйте язык обработки текстов, чтобы сгенерировать данные и или даже текст самой программы.

23. Совершенных программ не бывает. Бывают программы, которые легко поддерживать.

24. Пользуйтесь исключениями только в исключительных случаях.

25. Если запутались - применяйте закон Деметера. Но без фанатизма.

26. Настройка лучше интеграции. Текст программы - абстракция, метаданные - подробности.

27. Проектируйте, не забывая о службах - некоторые процессы так и просятся, чтобы их распараллелили. Для распределённых приложений - концепция доски объявлений.

28. Реорганизуйте чаще, раньше, регулярней.

29. Проектируйте с учётом тестирования. Тестируйте сами, иначе это будут делать пользователи. Применяйте, если надо, журнал или даже секретное отладочное окно (пользователю не говорить).

30. Работайте с пользователем, чтобы говорить на его языке.

31. Абстракции живут дольше потребностей. Поэтому, например, проекту нужен иногда глоссарий - что как называется.

32. Не размышляйте вне ящика = найдите его. Все возможные решения, включая безумные - в список и на проверку. Так же выпишите ограничения.

33. Вопросы, если упёрлись:

    Можно ли сделать проще?
    Мы решаем проблему, или увязли в деталях?
    Почему это проблема?
    Что делает её сложной?
    Нужно ли это?

34. Начинайте, когда знаете, что будете делать. Иначе дров наломаете.

35. Автоматизируйте всё.

    Генерация текстов - Perl
    Системные дела - Cmd, Cygwin (теперь и PowerShell)
    Тестирование интерфейса - есть и для этого средства (в наше время - iMacro, AutoIt)

36. Тестируйте беспощадно. Тестируйте в т.ч. сами тесты - специально поставьте неправильный вывод и т.п. и проверьте, найдёт ли его текст.

вторник, 8 мая 2012 г.

Script: скомпилировать все *.sln файлы

Ещё один CMD-скрипт. Делает Switch для tortoise, после чего перекомпилирует все *.sln в проекте.

@echo off
set MSBUILD=%WinDir%\Microsoft.NET\Framework\v3.5\msbuild
set PROJECT=d:\Projects\CSharp\MinesweeperProj\
TortoiseProc /command:switch /path:"%PROJECT%"
cd %PROJECT%
for %%f in (*.sln) do "%MSBUILD%" %%f
cd %~dp0.

К сожалению, switch с заменой ветки в текущей стабильной версии делать нельзя. В nightly версии у switch добавился параметр url, но бета-версии Tortoise на работе обычно не ставят.

Script: Скриптовая эволюция

Дано - написать скрипт, который кидает определённые файлы из локальной папки в папку на подключенном сетевом диске. Например, веб-проект, в котором мы изменили 2-3 dll. OS Windows.

На каком языке писать скрипт?

ActivePerl под Windows - иногда не принимает переданных параметров
Cygwin - нету
PowerShell - просто так даже Hello World не запустишь. Система будет ругаться, что он... не подписан (маразм? маразм!)

Похоже, технологии ушли слишком далеко. Нам остаётся только старый формат CMD файлов.

copydll.cmd:

@echo off
set FROM=d:\proj1\bin
set TO=W:\stable\proj1\bin
FOR %%A IN (%*) DO IF EXIST "%FROM%\%%A.dll" COPY /Y "%FROM%\%%A.dll" "%TO%\%%A.dll"

Добавляем папку в Path и вызываем

copydll Proj.Module1 Proj.Module2

А этот cmd можно кинуть на панель в Total Commander и просто перетаскивать туда нужный файл:

@echo off
set TO=W:\stable\proj1\bin
FOR %%A IN (%*) DO IF EXIST %%A COPY /Y %%A "%TO%\%%~nxA"

Конечно, можно просто перетащить на панель Total Commander'а саму папку, но тогда придётся дважды щёлкать мышкой (ОК в диалоге копирования и потом Replace All)

Да, ещё. Если написать в CMD-шке PAUSE, она в этом месте попросит Press any key to continue....

понедельник, 7 мая 2012 г.

Blog: Баг в ЖЖ

Продолжая тему перепостов - в ЖЖ обнаружен баг, позволяющий постить тексты намного длиннее разрешённых.

Дело в том, что если попытаться послать пост по e-mail (как это сделать - ищите в настройках. Там оно есть), то LJ то ли не будет проверять его размер, то ли будет проверять его по старому стандарту.

И пост благополучно уйдёт по назначению.

Писал на Хабр - НЛО статью отвергло. И правильно - неча умные вещи писать.

И, для изучение - Perl-скрипт для синхронизации Wordpress и Livejournal. Написано на Perl, запускать в cron.

Book: Программист-прагматик - 1. гл. 1-2

Книга довольно старая (эпохи, кажется, Windows 2000) и очень плохо переведена (есть глава “Мой исходный текст съел кот Мурзик”).

Набор инструментов типичен для того времени - C++, CORBA, Perl и т.п.

Внимательно читать не стоит, а вот просмотреть - надо. В книге есть мысли, которые просто в голову не приходили.

Полезное:

1. Предлагать варианты решения проблемы, а не отговорки.

2. “Закон разбитых окон” выполняется и для программ. Если есть ошибки и нестабильности - очень скоро их станет намного больше.

3. Качество должно быть одним из требований.

4. Читайте по одной технической книге ежеквартально. И другие книги - не относящиеся к технической литературе.

5. Экспериментируйте с различными операционными системами.

6. Оставайтесь в курсе событий - интернет и т.п.
(Советует журналы и news-группы - в духе времени. Сейчас закрылись и основной журнал по C++, и The Perl Journal. Статьи из последнего можно найти в Интернете по метке TPJ).
и критически осмысляйте всё, что нашли и услышали.

7. “Лучше быть проигнорированным, чем недооценённым”. Беседуйте с гуру и с потребителями.

8. Принцип для выступлений WISDOM:

- Чему вы хотите научить?

- Какова их заинтересованность?

- Насколько искушена аудитория?

- Насколько детальным должно быть выступление?

- Кто должен обладать информацией?
 
- Как мотивировать слушателей?

9. DRY - Don’t repeat yourself. Важно писать код так, чтобы его было легко использовать повторно. Тогда отпадает большинство эпизодов с дублированием.

10. Ортогональность - следует исключать взаимодействие между объектами, не относящимися друг к другу. Искать баги становится легче, код -- более удобным для повторного использования, и немного возрастает производительность.

11. Из 10 - подобные функции могут быть объеденены в Strategy, а глобальные данные - в Singletone

12. Обратимость. Вытекает из предыдущего. Помним, что не существует окончательных решений. Если чтобы заменить MS SQL на Oracle надо переписывать всё - это не порядок.

13. Чтобы стрелять ночью прицельно, используют трассирующие пули, которые светятся в темноте. Куда попадёт трассирующая - попадёт и обычная. Используйте “трассирующие” предложения, чтобы понять, что от вас хотят.

14. Прототипы (не работает, но показать можно):
- Архитектуры (классы-заглушки)

- Новых функциональных возможностей для системы (интерфейс, который не работает)

- Структуры или содержания внешних данных

- Компонентов

- Рабочих характеристик

- Интерфейса

15. “Границы моего языка есть границы моего мира”.

(Неспроста Хайдеггер искал истину в языке, иногда получая слова в духе Хлебникова)

Программируйте как можно ближе к предметной области вашей задаче. Если команды можно упаковать в классы-“пакеты” - пакуйте! Т. ж. хорошо писать мини-языки, там, где они могут пригодиться.

Если язык парсится, его лучше описать в BNF, которая годится для всех контекстно-свободных грамматик (Perl, например,ей не опишешь)

Т.к. срок службы большинства прикладных программ превышает ожидаемый, лучше, чтобы язык был гибче и удобочитаемей. Ближе к настройкам rc, чем к настройкам sendmail.

16. Проводите оценки по следующим градациям:

1-15 дней - дни

1 - 8 недель - недели

8 - 30 недель - месяцы

> 30 недель - надо хорошенько подумать

Если вы уверены, что проект займёт 125 рабочих дней (= 25 недель) - говорите “примерно 6 месяцев).

Если просят оценить сразу - говорите “надо подумать”. Ведите журнал оценок, чтобы знать свою точность. И по возможности сдвигайте график в ходе проекта - по мере работы он не растягивается, а уточняется.

суббота, 5 мая 2012 г.

Blog: Постим в два блога одновременно

Не люблю ЖЖ, но эккаунт там всё-таки есть. И хочется, чтобы блоги были синхронизированы. Чтобы написал здесь - а там оно само появилось.
Для этого есть разные способы.
  • Поставить Firefox + Scribefire. Добавляем в него оба наших блога и, когда делаем пост, ставим флажок на том блоге, в который нужно отправить копию. По-моему, лучшее.

    Особенности
    • Когда добавляем блог, надо указать имя, тип (для livejournal - "Livejournal (old)") и нажать "Следующий". Тогда он правильно определит URL.
    • Если в вашем логине есть дефисы, надо вводить их нижним подчёркиванием, e.g.: rikki_mongoose.
    • Крайне желательно, чтобы блог был оформлен как чёрный текст на белом фоне. Editor, который встроен в Scribefire, любит вставлять стилистический мусор и явно задаёт цвет для каждого абзаца. В моём случае получался текст "углём по чёрной бумаге". Замучившись, я просто отказался от идеи использовать 2 блога.
    
    
  • Настроить перепост через почту. Это дыра в безопасности - четырёхзначный PIN скорее всего будет годом рождения где-то между 1900-2000. Да и забить ящик Livejournal'а письмами с PIN-кодом от 1000 и 9999 - дело одного дня.
  • Воспользоваться сторонним сервисом перепоста, вроде Пистона. Работоспособность никто не гарантирует. И название у них дурацкое.

пятница, 4 мая 2012 г.

Life: Музыка паттернов проектирования

В "Русских Ночах" Одоевского очень много разговоров о музыке. В те времена рассуждали примерно так: у животных нет понятия о красоте, хотя есть понятие о логической связности мира (т.е., разум). Но человеку красота доступна. Не в этом ли его тайна? И ещё - из всех искусств музыка выглядит наиболее "бесполезной" и ни на что в материальном мире не похожей, в отличии от архитектуры, скульптуры, литературы и живописи. Не в ней ли тайна прекрасного?

Может быть, именно способность воспринимать прекрасное сделала человека человеком? Прекрасное чувствует и европеец, и древний грек, и древний египтянин. Даже дикарь с далёких островов Полинезии замирает, очарованный величественным водопадом, а вернувшись в хижину, он делает их дерева нарядные украшения. Напротив, филистёр этого лишён - и потому ближе к животному, чем к человеку.

Неспроста так популярно в ту эпоху система Шеллинга, а главным героем романтической прозы очень часто становится музыкант. Про музыку пишут так проникновенно, что и не снилось современному искусствоведу. Даже меркантильный человек наших дней заинтересуется классикой после "Себастиана Баха" и "Последнего концерта Бетховена". Искусство классической музыки сложно, красиво и, самое гласное, её много. Стройное здание классической музыки похоже на дворец - а кто из людей не хотел бы хоть недельку пожить во дворце?

Будет здорово, если хотя бы один программист отнесётся к своей работе ка персонажи эры романтизма относились к музыке. Сел за клавиатуру - и начал творить симфонию или кантанту, изобретая, переделывая и что-то отбрасывая. Конечно, есть ещё и заказчик... но у музыки барокко, Баха и Бетховена тоже были заказчики.

Кто знает - может, ремесло программиста станет тогда более возвышенным. А их код - более гармоничным.

Ведь программирование - это тоже искусство. Это выражается, например, в том, что программисты обычно сами не могут объяснить, как они делают то, что делают. Как у композиторов или у исполнителей - у величайших есть своя манера. Для кого-то и Perl недостаточно гибок, а для кого-то - например, для Линуса Торвальдса - и C++ есть излишество, эксплуатирующее достоинства чистого C.

суббота, 28 апреля 2012 г.

Cygwin: grep взбунтовался?

Интересные вещи творятся в GNU grep 2.5.4. С мест сообщают - grep -o - тормозит как неизвестно что.


Поэтому надо писать так:


gawk '{match($0, "REGEXP") ; if (RSTART) print substr($0, RSTART, RLENGTH);}'


А желающие могут сравнить:

#!/bin/sh
for x in {1..10000} ; do echo {a..z} @where=gdetotam@ {a..z}{a..z} ; done > tmp.txt
export LC_ALL=C
time cat tmp.txt | grep -o "@where=[^@]\+@" > /dev/null #медленно, 2 секунды
time cat tmp.txt | grep "@where=[^@]\+@" > /dev/null #быстро, 0.1 секунды
time cat tmp.txt | awk '{match($0, "@where=[^@]+[@]") ; if (RSTART) print substr($0, RSTART, RLENGTH);}' > /dev/null
На моём Cygwin с grep 2.5.1 - всё ОК.

Cygwin: Ловим ошибки

Не забываем добавлять в начало bash-скрипта (сразу после адреса):

set -euo pipefail

чтобы увидеть ошибки в коде, переменных и пайпах.

А вот ошибки в функциях нам так и не покажут.

C#: Number Range в Combobox

Например, нам нужно положить в telerik-оподобный control список из вот таких элементов:
< telerik:radcomboboxitem runat="server" text="2010" value="10" >

Такие штуки надо генерировать в одну строку:
private const int CC_VALID_YEARS_RANGE = 9;
....................................................................................
ddlYear.DataSource = Enumerable.Range(DateTime.Today.Year, CC_VALID_YEARS_RANGE)
                               .ToDictionary(item => item.ToString(),
                                             item => (item % 1000).ToString());
ddlYear.DataTextField = "Key";
ddlYear.DataValueField = "Value";
ddlYear.DataBind();
А если надо добавить ещё одну строку Year с пустым значением - нужно предварительно сбросить Dictionary в ToList() (получится List < KeyValuePair < string, string > >) и сделать insert в 0-ой индекс. Дело в том, что Dictionary<> сам по себе не сортируется - соответственно, Insert-а в нём нет и foreach перебирает его в том же порядке, в каком элементы добавились.
private const int CC_VALID_YEARS_RANGE = 9;
....................................................................................
List < nKeyValuePair < string, string > > yearsList =
              Enumerable.Range(DateTime.Today.Year, CC_VALID_YEARS_RANGE)
                        .ToDictionary(item => item.ToString(),
                                      item => (item % 1000).ToString()).ToList();
yearsList.Insert(0, new KeyValuePair < string,string > ("Year", String.Empty));
ddlYear.DataSource = yearsList;
ddlYear.DataTextField = "Key";
ddlYear.DataValueField = "Value";
ddlYear.DataBind();

Cygwin: Резервное копирование

Умеренно универсальный скрипт для резервного копирования. На входе - директория. Можно добавить дополнительные параметры. На выходе - она же, запакованная в tar.gz.

#!/bin/sh
BackUpDir="/cygdrive/D/Backup"
if ([ $1 ]) then
  BackUpDir=$1
fi
if ([ ! -d $BackUpDir ]) then
  mkdir -pv $BackUpDir
fi
if ([ $2 ]) then
 if ([ -d $2 ]) then
  From=$2
 else
  From=`dirs`
 fi
fi
ArchiveName="$BackUpDir/"`date +"%d.%m.%y(%H.%M)"``echo "$From" | sed 's!^\(/\?.*\)*/\(.*\)/\?$!\2!g'`".tar"
tar -cf "$ArchiveName" *
gzip $ArchiveName

Cygwin: Лучше, чем у Лекса Кравецкого

Во время оно lex-kravetski был не только коммунистом, но ещё и программистом. Например, написал большой пост о том, как конвертировать wav в mp3 консольным конвертером и 2 BAT-файлами.

При всем нашем уважении к пакетным файлам, то же самое на cygwin выглядит не в пример лучше, лаконичней и помещается в 1 скрипт:

#!/bin/sh
LameDir="C:/lame"
if ([ $1 ]) then
 Artist="$1"
else
 echo -n "Artist="
 read Artist
fi
if ([ $2 ]) then
 Genre="$2"
else
 echo -n "Genre="
 read Genre
fi
CurrentDir=`dirs`
ParamAlbum=`echo $CurrentDir | sed 's!^\(/\?.*\)*/\(\([0-9]\{4\}\)[ -]\+\)\?\(.*\)$!--ty "\3" --tl "\4"!g'` #RegExp: ^(/.*)*/(([0-9]{4})[ -]+)?(.*)$
for filename in *.wav
do
  FileShortName=`echo $filename | sed 's!\^(.*\).wav$!\1!g'` #RegExp: ^(.*).wav$
  ParamTrack=`echo $FileShortName | sed 's!^\([0-9]\{2\}\)[ -.]\+\(.*\)!--tn "\1" --tt "\2"!g'` #RegExp: ^([0-9]{2})[ -.]+(.*)
  echo "$LameDir/lame.exe -V2 \"$CurrentDir/$FileShortName.wav\" \"$CurrentDir/$FileShortName.mp3\" --pad-id3v2 --ta=\"$Artist\" $ParamAlbum $ParamTrack --tg=\"$Genre\""
done

Как использовать?
  1. Сохраняем скрипт в нашу директорию со скриптами под именем tomp3 (или ещё каким-нибудь). Во второй строке указываем директорию, куда мы распаковали Lame.
  2. Копируем файлы с CD в wav в таком виде:

    2009 - Album / 01 - Song.wav

    Или в другом:

    Album/01 - Song with a long-ling name.wav

    (год может быть и пустым)

  3.  Открываем cygwin И переходим в папку с Wav-ками
  4. Набираем SH ~/tomp3 "Artist" "Genre". Если без них - скрипт сам спросит.
  5. После завершения кодирования: rm *.wav
  6. И quit
К сожалению, скрипта с подсветкой синтаксиса для bash-скриптов у меня нет. Поэтому я подсветил как brush:perl. Получилось ярко и доступно.

BAT: Неизвестные факты из жизни пакетных файлов

Многие слышали про bat-файлы. Но не все знают что:

  1. Помимо BAT, были ещё CMD, WSH (Windows Script Host с поддержкой аж двух языков - JScript и VBScript), а чуть позже появился Power Shell. JScript и VBScript интересны тем, что были намного сложнее и непонятнее BAT. Но и на них писали.
  2. BAT работали ещё в DOS-е, поэтому его выполняет command.com. А вот CMD - это более новый формат, его выполняет cmd.exe. Поэтому лучше использовать расширение CMD.
  3. BAT и CMD не понимают вложенный if (то есть if может быть только на 1 уровне). Поэтому чтобы сделать условия, приходится рисовать блок-схему и расставлять везде GO TO. Да-да, ту самую блок-схему, которую ещё во времена "Мифического человеко-месяца" рисовали уже после завершения проекта.
  4. @echo off нужно, чтобы bat-ник не писал вызовы на экран.
  5. rem - это строка комментария.
  6. Если написать в файле script1.bat строку script2 (причём script2.bat существует - т.е. мы вызываем его как команду), то script2.bat запустится, а script1.bat - прекратит выполнение. Чтобы не прекращал, надо писать EXEC script2.
  7. Переход в директорию, где лежит скрипт - cd %~dp0.
  8. Можно поставить cygwin и наслаждаться *nix-овой командной строкой под Windows. Кстати, там можно вкладывать сколько угодно If-ов. А ещё можно поставить ActivePerl. К сожалению, писать скрипт прямо в командной строке у Perl под Windows не получится - не такой стандарт для кавычек.
  9. Параметры командной строки лежат в переменных  %1..%9. %0 - имя скрипта (без расширения). %10 и больше - нет.
  10. Включать-выключать сервисы из пакетных файлов - это просто:  Проверить:
    SC QUERY "XService" | find "RUNNING"
    IF not "%ERRORLEVEL%" == "0" GOTO StartService
    ................
    :StartService
    
     Запустить:
    NET START "XService"
    
     Остановить:
    NET STOP "XService"
    
  11. Откомпилировать и запустить пример для wxWidget:
    • Cоздаём в каталоге, прописанном в AUTOEXEC, вот такой makesample.cmd
      @echo off
      make -f makefile.bcc
      for %%f in (*.exe) do start %%f
      exit
      
    • Заходим в каталог с файлами
    • Запускаем (нужно, чтобы был установлен компилятор make)

пятница, 27 апреля 2012 г.

C++: Вопросы на собеседовании

"Вопросы на собеседовании по С++" - один из самых популярных запросов, по которым находят этот блог.

А значит, настало время расширить этот постинг.

Т.к. такие списки периодически пропадают из Сети, я буду делать свой - с приложенными ответами.

Итак, понеслось:
Напоследок - картинка от jia3ep-а.

среда, 18 апреля 2012 г.

Life: Bug

Поиск и устранение бага - 5 часов рабочего времени. Чтобы исправить, нужно было в одном месте заменить + на -.

четверг, 12 апреля 2012 г.

Sitecore: Не искать ли через SQL?

ASP.Net: Ловим Enter на TextBox

Как сделать, чтобы при нажатии Enter на TextBox "нажималась" определённая кнопка? Некоторые до сих пор рекомендуют безумный способ с добавлением невидимого TextBox. Но правильный вариант - это дописывать в Page_Load:

textBox.Attributes.Add("onkeydown", "if(event.which || event.keyCode){if ((event.which == 13) || (event.keyCode == 13)) {document.getElementById('" + buttonDoh.ClientID + "').click();return false;}} else {return true};");