Инструменты пользователя

Инструменты сайта



// MinGW и локали

Если коротко, то всё, что связано с std::locale в MinGW не работает. Точка.

Зато вполне себе работает функционал из Си:

std::locale::global(std::locale("")); // не установит текущую локаль
setlocale(LC_ALL, ""); // установит текущую локаль, у меня это Russian_Russia.Cp1251

// Пополняем шпаргалки по C++: неявно-генерируемые перемещающий конструктор и оператор присваивания

Статью изначально публиковал на хабре: http://habrahabr.ru/post/232775/. Здесь - для единства мыслей :)

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

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

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

Шпаргалки представлены в виде PDF файлов для печати на принтере A4, в виде картинки PNG, а также исходников в SVG.

// hex ↔ bin в уме

Однажды писал про двоичные литералы в GCC: 0b00100100, новый стандарт C++14 закрепил их в C++.

Но тут я хотел бы рассмотреть лёгкий способ перехода в уме между hex и bin представлениями.

// C++14: Done

Стандарт отправился в печать: https://isocpp.org/blog/2014/08/we-have-cpp14

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

// Сервис для анализа последовательностей

Удобный сервис для анализа последовательностей и поиска зависимостей и вывода формулы: http://oeis.org/

Удобно использовать для различных видов анализа, обратной разработки и т.п.

// erase_if

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

// Const correctness

Ничего нового, просто ссылки:

  1. http://www.cprogramming.com/tutorial/const_correctness.html - для чего нужно и почему, а так же логическая и побитовая константность.

Если коротко, то что даёт применение ключевого слова const везде, где это уместно:

  1. Уберегает вас от некоторых ошибок, связанных с внезапным изменением данных в каких-то вызовых. Т.е. добавляет безопасности.
  2. Автодокументирование кода: вы выдите const ⇒ вы знаете, что данные не меняются ни в этом вызове, ни далее по иерархии.

Побитовая константность - когда при вызове ни один бит структуры или класса не меняется.

Логическая константность - когда при вызове какие-то поля могут меняться, но данные, отвечающие за логику класса не изменяются.

Обычно последнее связано с полями, которые имеют спецификатор mutable. Для чего они нужны? Самый простой пример: экземпляр класса может использоваться из разных потоков. Писать может один поток, а читать другой. Логично, что метод для чтения будет константным. Так же логично, что чтение и запись следует защитить мьютексом. Но если мы попробуем заблокировать мьютекс в константном методе, получис ошибку компиляции. Понятно, что изменение мьютекса никак не влияет на логическую константность класса, поэтому его можно объявить mutable и спокойно защищать им данные.

Из примера выше можно сделать такое неформальное заключение:

Побитовая константностью - неиболее сильная. Логическая - более слабая.

// std::begin() и std::end()

С приходом нового стандарта эти две свободные функции появились в STL, в библиотеке итераторов (#include <iterator>). Кроме того, в примерах кода часто можно увидеть, что они используются на STL контейнерах вместо собственных методов .begin() и .end():

#include <iostream>
#include <vector>
#include <iterators>
 
using namespace std;
 
int main()
{
  vector<int> v{1, 2, 3, 4, 5};
 
  for (auto it = begin(v); it != end(v); ++it)
  {
    cout << "Number: " << *it << endl;
  }
 
  return 0;
}

Мне хорошо понятно, что эти функции отлично подходят для RAW-массивов, т.е. если в примере выше заменить:

vector<int> v{1, 2, 3, 4, 5};

на

int v[] = {1, 2, 3, 4, 5};

или даже

int v[]{1, 2, 3, 4, 5};

То весь остальной код менять не нужно. Удобно, причём мы защищены от подсовывания указателя вместо массива. Но почему они применяются для STL контейнеров?

Поиск по интернету дал только один ответ: для унификации. И только.

Т.е. ни по «кошерности» ни по скорости два этих подхода не отличаются. Чисто для единства вида.

Если у кого есть другие предположения - милости просим в дискуссию.

Ссылки

// Qt Creator и C++11

Небольшая заметка о том, как форсировать поддержку C++11 в парсере для различных билд-систем. Заметки касаются master-снапшота QTC (брать тут: http://download.qt-project.org/snapshots/qtcreator/master/latest/ или собирать из исходников).

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

// Nvidia Optimus

Дошли руки до включения данной фичи на моём ноутбуке. Всё оказалось не просто, а очень просто, в случае Linux Mint 16, всё делаем по инструкции: http://help.ubuntu.ru/wiki/bumblebee для Linux Mint 16 смотрим на версии убунты 13.10, для будущего Linux Mint 17 - 14.04.

За более детальными настройками: https://wiki.archlinux.org/index.php/Bumblebee_%28%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9%29

Если коротко:

  1. Включаем в биосе Nvidia Optimus, у меня стоит предупреждение, что тема только для Windows 7 и 8, тупо игнорим
  2. После перезагрузке в выводе
    lspci -nn | grep VGA

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

  3. Ставим дрова nvidia (проприетарные):
    sudo apt-get install nvidia-319-updates nvidia-settings-319-updates
  4. Ставим бамблбее:
    sudo apt-get install bumblebee bumblebee-nvidia primus primus-libs-ia32
  5. Ребутимся (а может и не нужно, но у меня на этом шаге Optimus был выключен в биосе, так что один фиг нужно было включить, но перелогиниться нужно точно, так как текущий пользователь был включён в группу bumblebee, что бы иметь возможность вызывать optirun).
  6. Профит!

После загрузки смотрим вывод

optirun --status

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

optirun [аргументы] <приложение> [аргументы приложения]

Для самых нетерпеливых, можно сравнить вывод двух команд:

glxinfo
optirun glxinfo

// Quake IV в Linux

Если при старте вылазит такое:

...using GL_NV_blend_square
...using GL_ARB_texture_compression
X..GL_EXT_texture_compression_s3tc not found
Fatal Error: Texture compression unavailable
Shutting down SDL subsystem
--------------- BSE Shutdown ----------------
---------------------------------------------
idRenderSystem::Shutdown()
Sys_Error: Texture compression unavailable

Нужно сделать следующее:

  1. Устанавливаем driconf, для deb-based: apt-get install driconf
  2. Запускаем его от простого пользователя
  3. На вкладке «Image Quality» включаем параметр «Enable S3TC texture compression even if software support is not available»

Всё, радуемся игре.

// Газ, газовые смеси и холод

Часто вижу непонимание того, как и почему должен работать газ на холоде. Была задумка скомпоновать всю полученную информацию воедино, но так сложилось, что все уже сделано за нас. Итак, подборка:

Дома дополню про вес баллонов, в т.ч. для «экспедиционных» 5 и 12л пропановых.

Но если кратко:

  1. Все смеси делаются из двух или более газов, обычно: пропан, бутан, изобутан.
  2. Пропан кипит при температуре -42 градуса по цельсию.
  3. Бутан кипит при температуре -1 градус цельсия.
  4. Изобутан кипит при температуре -12 градусов цельсия.

Отсюда видно, что чем в смеси больше пропана и меньше бутана, тем газ лучше будет работать в холодную погоду. Наиболее оптимальными на холода будут пропан-изобутановые смеси, где не меньше 20-25% пропана.

Чисто пропановые баллоны не делают по двум трём (на основании комментарие) причинам:

  1. опасность взрыва от перегрева в тёплое/жаркое время года;
  2. стоимость изобутана и бутана значительно меньше стоимости пропана.
  3. пропан не имеет запаха, поэтому бутан, как сильно вонючий, добавляют для контроля утечек газа.

Т.е. теперь, глядя на баллон, хотя бы примерно можно представлять как он будет вести себя на холоде. По субъективным наблюдениям: «новая» ковеевская смесь (изобутан 72%, пропан 22%, бутан 6%) работает хорошо до -20 градусов. Будет больше пропана и меньше бутана - на меньшую температуру можно рассчитывать.

Ну и сразу же по расходу или сколько планировать газа на маршрут, взято отсюда: http://kovea.ru/articles/information/portativnye-gazovye-ballony-i-gazovye-kartridzhi/, но, в целом, отражает суть (хотя по оценка на высоте + топление снега как раз получалось около 160 грамм):

Количество газа нужно брать рассчитывается индивидуально исходя из условий, в которых будете находиться, при использовании газовых горелок и плит из-за сильного ветра теплопотери будут огромные, обязательно докупите ветрозащитный экран или сконструируйте сами. Обычно примерный расчет газа идет такой:
1) 50 гр./чел в день – эконом..
2) 80 гр./чел в день - оптимальный вариант
3) 100 гр./чел в день – комфортные условия.
4) 100-300 гр./чел в день – альпинизм (растопить снег, обычно берется в 2е больше примерно 160-200 гр./чел в день).
Интегрированные системы могут сэкономить расход газа на 20-30%.

Есть ещё варианты котлов под обычные горелки, но с радиатором. Судя по тестам, радиатор даёт выигрыш по времени около 40%, по расходу газа 15-20%.

И дополнительно по массе баллонов, начну с непривычных, бытовых баллонов (эти данные для ориентировки, на шильдике самого баллона более точная информация указана):

  1. http://tourist.kharkov.ua/phpbb/viewtopic.php?t=7492 - мегаподборка по весу разных туристических баллонов газа (вес пустого баллона, вес полного)

// C++ и копирование перекрывающихся областей

Программируя на Си многие сталкивались с такими функциями как memcpy() и memmove(), по сути, функции делают одно и тоже, но вторая корректно отрабатывает ситуацию, когда области памяти перекрываются (на что появляются дополнительные накладные расходы).

В мире С++ никто не запрещает пользоваться этими функциями (часто эти функции используют различные механизмы оптимизации и могут статься быстрее своих собратьев из мира C++), но есть и более родное средство, работающее через итераторы: std::copy. Это средство применимо не только к POD типам, а к любым сущностям, поддерживающим итераторы. О деталях реализации в стандарте ничего не сказано, но можно предположить, что разработчики библиотеки не настолько глупы, что бы не использовать, оптимизированные memcpy()/memmove() когда это возможно.

Но по наитию, хочется посмотреть, а что там с пересекающимися областями (overlapping memory blocks)? Ведь задача, на самом деле, не такая уж редкая. К примеру, хотим мы читать MPEG-TS пакеты (размер каждого 188 байт, каждый пакет начинается с 0x47 /sync byte/) из какого-то потока, и есть вероятность, что первое (а может и последующее, либо имеем дело с M2TS контейнером, размер блока которого 192 байта и лишние 4 байта в большинстве случаем мы можем игнорировать) чтение может попасть на середину пакета. В таких случаях обычно делается так: вычитываем блок 188 байт, далее ищем байт синхронизации, если он в нулевой позиции - всё отлично, если нет, то данные от него и до конца, нужно переместить в начало блока, в освободившееся место нужно дочитать недостающу порцию, после чего пакет считается вычитанным и можно отдавать его на обработку.

Наглядно процесс копирования данных в начало блока можно показать этой картинкой:

Т.е. видим, что есть перекрытие. Логично, было бы применить какой-то аналог memmove(), но в стандартной библиотеке есть только std::move который делает совершенно не то. Но при этом, читая описание для std::copy (http://www.cplusplus.com/reference/algorithm/copy) видим следующую строчку:

The ranges shall not overlap in such a way that result points to an element in the range [first,last).

т.е. на самом деле, если начало области (result) куда копировать, лежит вне области [first,last), то всё должно быть ок. И это реально так.

Но посмотрим такую схему копирования с перекрытием:

пока не обращаем внимание на то, что result тут в конце. Смысл картинки в том, что блок памяти нужно сдвинуть с начала на какое-то смещение вперёд, соответственно если это смещение меньше размера сдвигаемого блока, то адрес назначения у нас будет лежать в пределах [first,last), таким образом условие применимости std::copy не соблюдаются. И если применить его, мы просто затрём данным в перекрывающейся области.

Но тут на помощь нам приходит его собрат, как раз решающий эту проблему: std::copy_backward, всё отличие этой функции в том, что он осуществляет копирование с конца. Т.е. для случая изображённой на второй картинке, он возьмёт (далее очень грубо, т.е. на самом деле last и result это указатели на конец блока, а ближайшие данные находятся по last-1 и result-1) элемент из last и ложится в result, далее из last-1 в result-1, далее из last-2 в result-2 и так далее.

Видно, что при такой схеме копирования, когда мы начнём писать в перекрывающуюся область, данные в ней уже будут обработаны. Т.е. для нас всё хорошо. Забавно, что условие применимости при перекрывающийся областях для std::copy_backward слово в слово повторяет данное условие для std::copy.

Итак, резюмируя, простое правило:

  • Если result < first («сдвиг блока к началу /или влево/»), то применяем std::copy, в качестве result указываем НАЧАЛО блока-назначения.
  • Если result > first («сдвиг блока к концу /или вправо/»), то применяем std::copy_backward, в качестве result указываем КОНЕЦ блока-назначения.

Текст является творческим переосмыслением англоязычной статьи: http://www.trilithium.com/johan/2006/02/copy-confusion, картинки взяты от туда же, пример из собственного опыта.

Референс:

PS Статья была опубликована на Habrahabr: http://habrahabr.ru/post/218451

// C++11 regex

В синтаксисе регулярок в GCC 4.8.1/libstdc++4.8 нет поддержки квадратных скобок: []. Пришлось использовать Boost.Regex

Ах да, пруф: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53631

// Калькулятор X11 Modeline

Да, времена, когда нужно было считать модлайны, дабы выжать из своего монитора и видюхи максимум уже прошли (вздох, вспомнив пару ADI Microscan 4V и S3 Trio 64V+). Но если вас настигла проблема или вдруг, как мне, для тестов, потребовалось нестандартное разрешение экрана, то вот простой калькулятор: http://www.arachnoid.com/modelines/

Ниже по тексту идёт теория, а так же информация о том, куда нужно вставлять полученный модлайн. Про калькулятор написал, что простой. Не хороший, а простой. Почему так? А потому, что очень много тонких настроек скрыто, по сути, вы задаёте жалемое разрешение и частоту обновления. Ну а для более тонкой настройки есть и другие, типа: http://xtiming.sourceforge.net/cgi-bin/xtiming.pl

В оффлайне, аналогами этих калькуляторов, пожалуй будут: gtf и xvidtune

Первая прячется в пакете (debian-based) xserver-xorg-core, вторая в пакете x11-xserver-utils.

Пользоватся gtf так же просто как первым описанным калькулятором, просто передаём ей разрешение и частоту на вход, получаем результат:

$ gtf 800 480 60

  # 800x480 @ 60.00 Hz (GTF) hsync: 29.82 kHz; pclk: 29.58 MHz
  Modeline "800x480_60.00"  29.58  800 816 896 992  480 481 484 497  -HSync +Vsync

Второй, в интерактивном режиме тюнинм.

// Китайская мультитопливная горелка BRS-8 и запчасти от Kovea

Итак, буквально перед новым годом стал обладателем горелки китайского производства BRS-8 brs-8.jpg

Плюс этой горелки - её цена. Мне она обошлась в 2200 рублей в местном магазине во Владивостоке. Естественно встал вопрос надёжности отдельных частей, всё же «китай» в России уже термин нарицательный, описывающий определённое качество товаров, крайне далеко отстоящее от положительного.

Гугление особо ничего не дало, многократных подтверждений и особых болезней тоже не было выявлено, но получилось выделить следующее (наиболее собрано получилось тут: http://www.youtube.com/watch?v=jEds1uRhWkI):

  1. Износ шланга, травление в районе крепления к штуцеру со стороны регулятора и крепления к самой горелки
  2. Износ регулятора, начинает сифонить, при этом изнашивается не резиновые прокладки, а металл (!!!)
  3. Насос, точнее резьба, которая вкручивается в баллон, из-за своей пластиковой природы изнашивается. У некоторых сифонит по периметру, в месте вхождения насоса в пробку.

Логичным путём было поискать возможные замены для отдельных узлов и агрегатов. И тут… у меня родилась мысль…

В названии этой горелки в разных каталогах встречается приписка «Booster +1», что как бы намекает на отношение этой горелки к Kovea KB-0603 Booster +1. Действительно, визуальное сравнение по фотографиям приводит только к следующим различиям:

  1. форма ног самой печки;
  2. наличие бутылки в комплекте BRS-8
  3. более скудный ремкомплект у BRS-8
  4. отсутствие переходника на цанговый баллон у BRS-8

Всё. Визуальных конструкционных раздичий больше не наблюдается. Шланг, регулятор, насос, рассекатель пламени (он и оригинального бустера нередко теряется) похожи как, почти, две капли воды. Сами поглядите: koveabosster1.jpg

Соответственно было решено попытаться заказать комплектующие от оригинального бустера, примерить на китайский BRS-8 и посчитать результирующую стоимость полученного мутанта.

Насос, пока, было решено не покупать, а когда потребуется, взять в местном магазине (ровно как и ремкомплект и переходник на цанговый баллон). Шланг, регулятор и рассекатель пламени брались на http://kovea.ru. При этом, в каталоге их нет, поэтому нужно писать на eshop@kovea.ru или service@kovea.ru. Стоимость этих позиций узнаётся в этом разделе: http://kovea.ru/page/service/. Жителям Москвы будет проще лично забрать необходимые позиции там, для удалёнки, оплата через робокассу (почти все возможные методы оплаты) и доставка EMS или другой курьерской службой.

Подкатом много картинок. Здесь и далее все изображение кликабельны.

// PlantUML: параллельное выполнение в Sequence Diagram

Давно хотелось иметь в PlantUML возможно в Sequence диаграмме рисовать две параллельные ветки выполнения (на самом деле иногда больше, но хотя бы…).

И вот, случайно в последней версии нащупал такую команду:

par2
  ...
else
  ...
end

Т.е. при примерно таком коде:

@startuml
hide footbox

A++
par2
    A -> B ++
    B -> B ++
    return
    return
else
    A -> C ++
    C -> C ++
end
A--

@enduml

мы получим следующую картинку:

в общем, чего и хотелось.

Правда при таком подходе, если, допустим, A, B и C - разные потоки, то операции с A нужно корректно вставлять в одну из веток par2

PS в примере можно видеть различные операции типа ++ и найти их описание можно здесь: http://plantuml.sourceforge.net/incubation.html

// Прототипирование UI для мобильных приложений на бумаге

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

  1. Блокноты для прототипирования: http://onapkin.com/shop/ удобны, но не обязательны
    1. Ещё блокноты:
  2. Программа для склейки и анимирования: https://popapp.in/, там же: демонстрация работы.
  3. Статья на хабре про трафарет для iPhone: http://habrahabr.ru/post/209002/, трафареты для Android на сайте производителя:

Особнячком, русский магазин, который возит на заказ: http://moiprototip.ru/

// Wifi на Asus X551C

Не думаю, что проблема дистрибутивно-специфичная, но писать буду про Linux Mint 16.

Итак, имеем проблему: при загрузке с CD и уже в самой системе после установки у нас заблокирован Wifi:

user@user-X551CAP ~ $ rfkill list
1: phy0: Wireless LAN
	Soft blocked: no
	Hard blocked: yes
2: asus-wlan: Wireless LAN
	Soft blocked: no
	Hard blocked: no
3: asus-bluetooth: Bluetooth
	Soft blocked: no
	Hard blocked: no
4: hci0: Bluetooth
	Soft blocked: no
	Hard blocked: no

Обращаем внимание на строку

Hard blocked: yes

для устройства phy0. Обычно такое бывает когда карта выключена или через BIOS или через переключатель корпусе ноутбука. В случае конкретной модели Asus это состояние должно переклчаться через Fn-F2. Да вот беда: не работает эта комбинация. Вызов acpi_listen молчит как партизан при нажатии этой кнопки.

Но самым шоком стало то, что после засыпания и просыпания карта включалась! Собственно это стало поводом к поиску. И… первым воркэраундом :)

Перебирая выводы команд lspci -nn, lsmod, изучил какие модули используются. Особо заинтересовали модули из серии wmi - Windows Management Instrumentation и, в частности, asus_nb_wmi отвечающий, судя по всему за трансляцию различных клавиатурных эвентов, и его опция wapf, которая, судя по интернетам, отвечает за поведение клавиш включения/выключения Wifi и Bt.

Итак, погуглив по интернетам, нахожу следующие ссылки:

В общем, вроде как у некоторых проблему решает. Забегая вперёд хочу отметить: wifi заработал со значением wapf равным единице, но сама клавиша Fn-F2 - нет. Пробовать начинал с 0. Беда в том, что просто перегрузка модуля не помогает, нужно или полностью перегружать модули для карты и всего сопутствующего или просто перегружать комп.

В общем решение: создаём файл /etc/modprobe.d/asus.conf следующего содержимого:

options asus_nb_wmi wapf=1

и перегружаем комп.

Отмечу, что ещё до этого решения я задал через параметры ядра (задал в /etc/default/grub.conf) следующие настройки:

GRUB_CMDLINE_LINUX_DEFAULT="... rfkill.master_switch_mode=2 rfkill.default_state=1"

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

Ссылки по теме:

// Смайлы в Unicode

https://gist.github.com/endolith/157796 и http://www.alanwood.net/unicode/emoticons.html

Краткая выдержка, есть вероятность, что не во всех шрифтах будет отображаться корректно:

☹
☺
☻
♾
〠 smile in hat
ツ
㋡
😁
😃
😆
😇
😈
😉
😊
😋
😌
😎
😏
😐
😞
😠
😣
😲
😹
😺

// KDevelop 4.6 в Linux Mint

Ставим из PPA kubuntu-ppa/backports. Подробности:

А если коротко:

sudo add-apt-repository ppa:kubuntu-ppa/backports 
sudo apt-get update
sudo apt-get install kdevelop

// LyX и вёрстка в три колонки

Ничего необычного, используем пакет LaTeX multicols: http://tex.stackexchange.com/questions/78294/lyx-3-column-document Колонок может быть и больше :)

И на будущее нужно ознакомиться с LyX FAQ: http://wiki.lyx.org/FAQ/FAQ в частности, там есть информация как убрать дату из заголовка. Здесь же в совете номер 5 есть информация как копипастить таблицы из Open- и LibreOffice.

// Android SDK/NDK в Linux Mint

Просто последовательность действий - на память (брать из PPA не хотелось). Как качать NDK, SDK и Android Studio я расписывать не буду. Распаковку всего этого добра произвёл в ~/Android. Имена директорий привёл к виду (или переименованием или созданием необходимых симлинков):

  • android-sdk
  • android-ndk
  • android-studio

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

Итак…

Необходимое

  1. Ставим OpenJDK: sudo apt-get install openjdk-7-jdk libswt-cairo-gtk-3-jni libswt-cairo-gtk-3-jni ant
  2. В ~/.profile или ~/.bashrc_profile прописываем:
    export ANDROID_HOME=$HOME/Android/android-sdk
    export ANDROID_NDK=$HOME/Android/android-ndk
    # For compability
    export NDK_HOME=$ANDROID_NDK
    export ANDROID_SWT=/usr/share/java
    export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$ANDROID_NDK:$HOME/Android/android-studio/bin
    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ANDROID_HOME/tools/lib
  3. Переходим в ~/Android/android-studio/bin и выполняем:
    ln -s studio.sh android-studio
  4. Добавляем следующие параметры в studio.vmoptions и studio64.vmoptions (предварительно сделайте резервные копии, пригодятся при обновлениях):
    -Dswing.aatext=true
  5. На этом шаге можно перелогиниться, вызвать android и поставить платформы, утилиты, потом запустить Android Studio и сделать необходимые настройки.

Опциональное

Ярлыки в меню

FIXME относительные пути к иконкам не воспринимаются, поэтому иконки не отображаются, только текст.

  1. Создаём файл: ~/.local/share/applications/android-sdk.desktop со следующим содержимым:
    [Desktop Entry]
    Encoding=UTF-8
    Name=Android SDK
    Comment=Android Sofware Development Kit
    Exec=android
    Icon=~/Android/android-sdk/tools/apps/SdkController/res/drawable-xhdpi/ic_launcher.png
    Terminal=false
    Type=Application
    Categories=IDE;Development;

    Если иконка не будет отображаться, замените на полный путь.

  2. Извлекаем иконку Android Studio:
    unzip -o lib/resources.jar artwork/icon_AS_128.png

    Вызываем команду из корня android-studio

  3. Создаём файл: ~/.local/share/applications/android-studio.desktop:
    [Desktop Entry]
    Version=1.0
    Type=Application
    Name=Android Studio
    Exec=android-studio %f
    Icon=~/Android/android-studio/artwork/icon_AS_128.png
    Comment=Develop with pleasure!
    Categories=Development;IDE;
    Terminal=false
    StartupNotify=true
    StartupWMClass=jetbrains-android-studio
    MimeType=application/x-extension-iml;

Автодополнение BASH

Автодополнение для команд android, adb, emulator, fastboot и repo.

  1. Идём в ~/Android
  2. Забираем последнюю версию скрипта (предполагаю, что git уже установлен):
    git clone https://github.com/mbrubeck/android-completion.git
  3. Создаём файл ~/.bash_completion и помещаем в него:
    . $HOME/Android/android-completion/android
    . $HOME/Android/android-completion/repo
  4. Перелогиниваемся

// Infinality в Linux Mint & Ubuntu

Готовый PPA: https://launchpad.net/~no1wantdthisname/+archive/ppa описание там же.

UPD: ломает загрузку минта в графику к чертям собачьим. НЕ ИСПОЛЬЗОВАТЬ

UPD2: мужики нашли workaround: http://forums.linuxmint.com/viewtopic.php?f=208&t=136307. Не пробовал

UPD3: применил решение из UDP2, только поместил в более логичное место: ~/.profile. Система работает. А то смотреть без слёз на рендеринг шрифтов в QtCreator'е было нельзя.

UPD4: Сохраню тут для потомков и собственного удобства:

# move infinality-settings out of system profile
sudo mv /etc/profile.d/infinality-settings.sh /etc/infinality-settings.sh
 
# make execute by everyone
sudo chmod a+rx /etc/infinality-settings.sh

а уже вызов /etc/infinality-settings.sh добавить в ~/.profile

Хотя в той же теме на форуме, сказано, что исправлено в mdm (его вообще мог зафейлить любой косяк в /etc/profile.d/*): https://github.com/linuxmint/mdm/commit/ee1a28b3c295c283aa94b890658d78be25e31bb7 и доступно всё это в Mint 17.2 'Rafaela'. Альтернативной апдейту: отредактировать /etc/init/mdm.conf согласно патчу.

// LyX в Linux Mint и русский

Что бы в LyX начали сходу работать русский нужно поставить пакеты: texlive-lang-cyrillic и cm-super. Точнее даже не так: набивать тексты вы сможете сразу, а вот генерировать PDF - только после установки пакетов.

// Linux Mint Petra и встроенная ATI/AMD RS880 [Radeon HD 4250]

Внезапно, при логине в систему (иксы) выдалось, что рендеринг у меня софтовый. Хотя пакет с драйвером radeon стоял. Изучение /var/log/Xorg.0.log указало на то, что не получается загрузить модули ati и fglrx. При этом нет попыток грузить модуль radeon:

$ cat /var/log/Xorg.0.log  | grep "ati\|radeon\|fglxrx"
[   990.107] Build Operating System: Linux 3.2.0-37-generic x86_64 Ubuntu
[   990.107] Current Operating System: Linux gaz-work 3.11.0-13-generic #20-Ubuntu SMP Wed Oct 23 07:38:26 UTC 2013 x86_64
	(++) from command line, (!!) notice, (II) informational,
	Using a default monitor configuration.
[   990.109] (==) Automatically adding devices
[   990.109] (==) Automatically enabling devices
[   990.109] (==) Automatically adding GPU devices
[   990.109] 	X.Org ANSI C Emulation: 0.4
[   990.113] Initializing built-in extension XVideo-MotionCompensation
[   990.114] (II) Module glx: vendor="X.Org Foundation"
[   990.114] (==) Matched ati as autoconfigured driver 1
[   990.115] (==) Matched ati as autoconfigured driver 3
[   990.115] (II) LoadModule: "ati"
[   990.116] (WW) Warning, couldn't open module ati
[   990.116] (II) UnloadModule: "ati"
[   990.116] (II) Unloading ati
[   990.116] (EE) Failed to load module "ati" (module does not exist, 0)
[   990.117] (II) Module vesa: vendor="X.Org Foundation"
[   990.117] (II) Module modesetting: vendor="X.Org Foundation"
[   990.118] (II) Module fbdev: vendor="X.Org Foundation"
[   990.118] (==) Matched ati as autoconfigured driver 1
[   990.118] (==) Matched ati as autoconfigured driver 3
[   990.119] (II) LoadModule: "ati"
[   990.120] (WW) Warning, couldn't open module ati
[   990.120] (II) UnloadModule: "ati"
[   990.120] (II) Unloading ati
[   990.120] (EE) Failed to load module "ati" (module does not exist, 0)

Почесав макушку, решил попытаться «помочь» серверу, подтолкнув его в нужном направлении. Для чего идём в /etc/X11 создаём каталог xorg.conf.d, а в нём файл radeon.conf (используя любой редактор на своё усмотрение) со следующим содержимым:

Section "Device"
    Identifier "radeon"
    Driver "radeon"
EndSection

Сохраняемся, перелогиниваемся, радуемся отсутствию предупреждения о софтовом рендеринге. Проверяем:

$ cat /var/log/Xorg.0.log  | grep "ati\|radeon\|fglxrx"
[  2082.177] Build Operating System: Linux 3.2.0-37-generic x86_64 Ubuntu
[  2082.177] Current Operating System: Linux gaz-work 3.11.0-13-generic #20-Ubuntu SMP Wed Oct 23 07:38:26 UTC 2013 x86_64
	(++) from command line, (!!) notice, (II) informational,
[  2082.178] (**) |   |-->Device "radeon"
	Using a default monitor configuration.
[  2082.178] (==) Automatically adding devices
[  2082.178] (==) Automatically enabling devices
[  2082.179] (==) Automatically adding GPU devices
[  2082.179] 	X.Org ANSI C Emulation: 0.4
[  2082.183] Initializing built-in extension XVideo-MotionCompensation
[  2082.184] (II) Module glx: vendor="X.Org Foundation"
[  2082.184] (II) LoadModule: "radeon"
[  2082.185] (II) Loading /usr/lib/xorg/modules/drivers/radeon_drv.so
[  2082.219] (II) Module radeon: vendor="X.Org Foundation"
[  2082.236] (II) RADEON(0): Creating default Display subsection in Screen section
[  2082.248] (II) Module exa: vendor="X.Org Foundation"
[  2082.313] (II) Module fb: vendor="X.Org Foundation"
[  2082.313] 	ABI class: X.Org ANSI C Emulation, version 0.4
[  2082.313] (II) EXA(0): Driver registered support for the following operations:
[  2082.313] (II)         Composite (RENDER acceleration)
[  2082.313] (II) RADEON(0): Acceleration enabled

и

$ glxinfo |grep -i render
direct rendering: Yes
OpenGL renderer string: Gallium 0.4 on AMD RS880

До этого вместо AMD RS880 выводилось следующее:

$ glxinfo | grep -i render
direct rendering: Yes
OpenGL renderer string: Gallium 0.4 on llvmpipe (LLVM 3.3, 128 bits)

Собственно всё.

// Firefox и быстрый поиск

Все - не все, но многие знают, что в Firefox, Google Chrome и, вроде, Опере можно в свойствах закладки указать т.н. ключевое слово (keyword), набрав которое в адресной строке браузера и нажав Ввод перейдёшь по ссылке, на которую указывает данная закладка.

Удобно? Кому как. Но! У этого функционала есть ещё одно одно применение.

Дело в том, что в самом адресе закладки можно указать подстановочную последовательность (плейсхолдер, placeholder, уж не знаю как более корректно перевести это слово на русский язык) %s. На это место будет подставлен весь текст который будет введён после ключевого слова.

На пальцах. Допустим, у нас есть закладка, у которой ключевое слово g, тогда, если в адресной строке введём:

g ябеда-корябеда солёный огурец

то вместо %s будет подставлено: «ябеда-корябеда солёный огурец»

Теперь чуете? Правильно! Мы можем вызывать какие-то URL с параметрами. Это общий случай, я же, в основном, использую это для поиска. К примеру, у меня такой набор (жирным выделены названия закладок):

Да, в самом Firefox можно ключевые слова задать для существующих поисковых систем (в Search bar), но вручную там нельзя добавить произвольную (задав только URL для поиска), только установкой соответствующего расширения, которого может не оказаться. Плюс метод работает во многих браузерах, так что импортировав закладки, получите и работающий поиск, к которому привыкли.

В luakit это сделано прямо и ровно через технологию Search Engine. Пример можно посмотреть прямо в коробке в файле globals.lua (или тут).

// ps2pdf и отрицательное смещение сверху

Если при преобразовании PS в PDF на выходе наблюдается отрицательное смещение (как бы часть листа срезана) сверху, то стоит попробовать явно задать формат страницы при преобразовании:

ps2pdf -sPAPERSIZE=a4 input.ps output.pdf

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

// Эффект плазмы

Во многих системах есть хранитель экрана который показывает примерно следующее:
plasma_effect.jpg

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

// Владивосток: УК "Дальневосточный регион" и смена сантехники

Не вызывайте их сантехников, особено не для аварийных работ, типа смены сантехники /канализация, унитаз/, монтажа разводки:

  • В понедельник будем вызывать заново, т.к. течёт унитаз по эксцентрику, а сегодня ещё обнаружилась течь на месте стыка новой фановой трубы со стоячной. Из-за небольшой лужи, которая образовалась при пробных запусках, после проливки не заметил
  • Разводку делают не аккуратно, про обводы /для обхода труб/ узнал сам из интернет.
  • Не смонтрировали узел с счётчиками до начала кладки плитки /были онформированы/, в результате местер, кто делал ремонт неверно посчитал размер короба, как следствие - результат далёк от ожидаемого.
  • Стоимость при этом достаточно кусачая, и даже примерная смета отличается от списка работ на сайте компании.
  • Наша ошибка, не затребовали составление договора, акт выполненых работ сделан только в одном экземпляре, который, естественно, остался не у нас. Ни компания, ни сами мастера даже не предложили. Смета работ тоже не составлена.
  • Неверно посчитали материалы, как результат пришлось два раза дополнительно бегать покупать /для установки змеевика, унитаза/
  • Не позвали, когда прикручивали змеевик, в результате утопили в короб /ещё не смонтированный/, пришлось просить «выдвигать», дырки на новом кафеле «приятно» дополняют внешний вид.

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

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

Сайт: http://www.dvregion.vl.ru

// Luakit и Readability.com

Чуть более года назад выложил свои конфиги для Luakit на гиториусе: https://gitorious.org/hatred-configs/luakit/

Помимо подстроек под себя, там же был реализован URI-rewriting. Правда использовал только для хабра, что бы адрес преобразовался по следующему правилу:

http://habrahabr.ru/post/196966/ --> http://m.habrahabr.ru/post/196966/

дабы избавится от рекламы, флеша и лишнего форматирования.

Вчера же добавился функционал для сохранения страниц на сервисе отложенного чтения readability.com. Сделано полностью в виде отдельного модуля (в отличии от URI-rewrite). По умолчанию заданы следующие комбинации клавиш:

  • vv - смотреть страницу через readability
  • vs - сохранить для отложенного чтения
  • vg - открыть сайт readability.com в новой вкладке

У функционала «смотреть страницу через readability» внезапно оказалось одно интересное и полезное побочное свойство: просмотр страниц, попавших в немилость роскомнадзору.

Enjoy! :-)

TODO добавить функционал для открытия сайта через http://anonymouse.org/cgi-bin/anon-www.cgi/URL или:

// Big-endian и little-endian: шпаргалка

Big-endian Little-endian
Формулировка Старшие разряды (байты) - первые Младшие разряды (байты) - первые
Запись M = sum{i=0}{n} {A_i} * {B^i} = A_0 * B^0 + A_1 * B^1 + cdots + A_n * B^n
B - база системы счисления, для dec - 10, для hex - 0xFF или 256.
A_0 - младший разряд, A_n - старший разряд
An, …, A1, A0 A0, A1, …, An
1024 (dec), 0x0400 (hex)
dec 1, 2, 0, 4 4, 0, 2, 1
hex 0x40, 0x00 0x00, 0x40
Синонимы Network byte order
Motorola byte order
Intel byte order
VAX order
Использование Обычная для человека1) запись чисел (в том
числе шестнадцатиричных в C/C++ и других)
TCP/IP
PNG
Числа в памяти на x86 и некоторых других
USB
PCI
1)
Для письма слева-направо

// Пароль BIOS на ноутбуке Toshiba

Дома настраивал ноутбук Toshiba матери. При включении сразу меня поприветствовала такая надпись:

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

Но сначала решил попробовать стандартные варианты тыпа qwerty и иже с ними. При этом, после окончания попыток наблюдал такую картинку:

Этот номер меня немного заинтересовал и забил я этой CRC в гугле на поиск. Изыскания привели к этой статье: http://dogber1.blogspot.co.uk/2009/05/table-of-reverse-engineered-bios.html, где рассказывается про алгоритм как получить подходящий пароль, контрольная сумма которого будет такой же как и у неизвестного. Там же в конце идёт ссылка на сайт Вячеслава Бачерикова, который реализовал этот алгоритм на JavaScript:

Первый же пароль от туда подошёл к системе (хотя нотбука и нет среди «поддерживаемых»). Так что даже не пришлось разбрать ноут и сбрасывать настройки CMOS.

Одно не понимаю, нафига все эти защиты, если они обходятся достаточно не сложным анализом и поиском в гугле?

// На заметку: чисто виртуальные функции с определением

Да, речь про такое:

struct Foo {
  virtual ~Foo()      = 0; // [1]
  virtual void proc() = 0; // [2]
};
 
// [3]
Foo::~Foo() {
  // some actions
}
 
// [4]
void Foo::proc() {
  // some actions
}

[3] и [4] для [1] и [2] соответственно могут находится в другом файле.

Информации в интернете много, поэтому заметка для себя, ибо где-то пропустил в изучении. Далее мои домысли и моё понимание проблемы.

Начнём с [2].

Такое нужно:

  1. когда требуется, что бы в наследниках эти функции были обязательно определены (т.е. были чисто виртуальными в базовом),
  2. но при этом требуется, что бы была предоставлена реализация по умолчанию.

Например:

struct Bar : Foo {
  virtual void proc() {
    // здесь полностью своя реализация
  }
};
 
struct Baz : Foo {
  virtual void proc() {
    // а здесь мы позвали реализацию по умолчанию.
    Foo::proc();
  }
};
 
struct Bak : Foo {
  // а такой класс мы инстанцировать не сможем
};

А теперь про [1]

Начнём с того, что деструкторы, по иерархии, не переопределяются и при уничтожении объекта вызываются все деструкторы до базового класса и если деструктор будет чисто виртуальным, то получим такую ошибку, ещё на этапе компиляции:

/tmp/cc42YqK5.o: In function `Bar::~Bar()':
main.cpp:(.text._ZN3BarD2Ev[_ZN3BarD5Ev]+0x1f): undefined reference to `Foo::~Foo()'
collect2: error: ld returned 1 exit status

Т.е. тело у деструктора должно быть всегда (ну не совсем, см. ниже). Так когда возникает необходимость сделать деструктор базового класса чисто виртуальным с определением? Мне в голову пришло только:

  1. сделать класс чисто виртуальным, не объявляя ни одной чисто виртуальной функции.
  2. сделать класс только со статическими членами и запретить создание объектов этого типа, помогает защититься от дружественных классов и функций и просто от наследования (помещение конструктора по умолчанию в приватную секцию не спасёт от френдов). В этом случае, кстати, делать определение для чисто виртуального деструктора не обязательно.

Поясню. Если сделать так:

struct Virtuable {
  virtual ~Virtuable() {}
};

Все классы-наследники автоматом будут с виртуальными деструкторам, но при этом мы можем сделать такое:

Virtuable f;
Virtuable *p = new Virtuable;

Т.е. мы можем создать объекты-пустышки. А зачем нам это? Если же объявить класс так:

struct Virtuable {
  virtual ~Virtuable() = 0;
};
 
Virtuable::~Virtuable() {}

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

Имхо, может быть полезно во всяких фабриках.

// Мысли о DPI

Точнее о DPI2) мониторов.

Очень вяло задавался вопросом, почему на моём маленьком, слабеньком, не сильно дорогом Asus EeePC 1000HA изображение на мониторе отличное, почти все шрифты выглядят нормально, а почти на всех новых, рабочих мониторах с диагональю 24 дюйма и фулхд разрешением, полная беда, что в Linux, что в Windows.

Да, можно покрутить ручки fontconfig или поставить mactype, но всё равно: на нетбуке же я не крутил!

2)
Dots Per Inch [точек на дюйм] - мера разрешающей способности чего либо: монитора, принтера и т.п.

// Logitech Unifying и Linux

Кратко: Logitech Unifying Receiver приёмник у беспроводных устройств Logitech к одному которому можно слинковать до 6 устройст. При этом устройство, с которым вместе идёт приёмник уже заранее слинковано с ним и работает из коробки.

Проблема в том, что бы добавить новое устройство. Для этого нужен софт, и софт этот -есть- был только под Windows и под Mac OS X. Хорошо, что слинковав устройства на одном компе можно было использовать их на остальных без проблем. Но, согласитесь, не удобно.

// Онлайн компиляторы C/C++ и не только

Иногда нужно быстро проверить работоспособность какой-то идеи или алгоритма. Хорошо, когда у вас Linux и какая-то система из семейства Unix с установленным компилятором (имхо, в 90% случаев это будет правдой), вам просто нужно открыть консоль вызвать vim/emacs/joe/mcedit/etc набросать программку и вызвать компилятор. Но иногда вы в гостях/командировке/интернет-кафе, в общем тогда, когда компилятора нет под рукой, но есть доступ в интернет. Тут помогут онлайн-компиляторы.

// Забавный баг

Есть некая система (embedded), у которой вся память поделена на пулы различного размера и способы выделения память (фиксированный размер, переменный размер). Есть механизм для выделения памяти из этих пулов (на основе размера аллокации подбирает подходящий пул и делает от туда выделение) и возвращение её туда, примем его таким:

void *pool_alloc(size_t size); // выделение памяти из пула
void *pool_calloc(size_t size); // выделение памяти из пула и зануление её
void pool_free(void *ptr); // возврат (освобождение) памяти в пул

есть так же определённые операторы new/new[]/delete/delete[] для использования этого механизма в C++ коде (код сильно упрощён):

void* operator new (size_t size)
{
    return pool_alloc(size);
}
 
void* operator new[] (size_t size)
{
    return pool_alloc(size);
}
 
void operator delete (void *ptr)
{
    pool_free(ptr);
}
 
void operator delete[] (void *ptr)
{
    pool_free(ptr);
}

На этом вводная часть закончена. Переходим к сути.

Существовала испокон веков некая большая структура (в терминологии C++ - POD тип), и код, использующий её был повсеместно на чистом C. Назовём эту структуру так:

struct BigStruct 
{
    // a lot of fields
};

Соответственно память под эту структуру выделялась и освобождалась так:

...
big_struct_ptr = (struct BigStruct*)pool_calloc(sizeof(struct BigStruct)); // память сразу занулялась
...
pool_free(big_struct_ptr);
...

Время шло, код постепенно «переписывался» на C++. В кавычках, потому как это «переписывание» сводилось к изменению расширения файла на .cpp и исправлению очевидных ошибок и предупреждений (тут, с одной стороны, используется -Werror как опция для GCC, с другой стороны, предупреждение включены далеко не все). И вот, в один прекрасный момент, весь код, который использует эту структуру, уже компилируется C++ компилятором. Как результат, при очередной фиче или багофиксе в структуре появляется поле типа

std::vector<Foo> some_field;

То есть, одним мановением руки, структура перестаёт быть POD-типом, но… Механизм выделения и освобождения памяти для неё не меняется!

Теперь сделайте паузу и пофантазируйте, к чему это приводит.

На практике, это решение жило около двух лет (на момент написания статьи) и никак себя не проявляло. А приводило оно к постепенной утечке памяти: для std::vector не вызывался ни конструктор ни деструктор. Отсутствие вызова конструктора проходило незаметно, в этом конкретном примере «спасало» то, что память занулялась и у класса нет vtable. А вот отсутствие вызова деструктора приводило к тому, что все аллокации, сделанные внутри вектора, не освобождались. Маскировало эту проблему то, что аллокации были очень маленькие (около 4 байт), и их было немного за весь период нормальной работы аппарата от момента включения до выключения.

Выявило нагрузочное тестирование, где один алгоритм прогонялся атипичное, для нормальной работы, количество раз (помогло логирование вызовов new при помощи gcc'шной __builtin_return_address(), objdump -d и базовые знания ассемблера).

// Qt Creator и perforce

UPD: Изменения, на основе этого патча, заинтегрированы в Qt Creator другим человеком. От меня была только ревью кода.

Во времена, когда проект Qt и все смежные тулы были под управлением VCS Perforce, появился плагин для Qt Creator'а для интеграции работы с этой системой, да вот только в своём развитии он конкретно и застрял в тех стародавних временах. Причина проста: проект переехал на Git, а перфорс нафиг никому не сдался. Как результат: плагин есть, и даже собирается, да вот только считать его хоть малость рабочим… не получается.

Как минимум одна особенность (читать бага), перечёркивает весь (и без того убогий) функционал: он не может определить директорию верхнего уровня для файлов.

При этом, это вроде как работает, когда забиваешь настройки, да вот только они там и поселяются навсегда, прибитые к одному серверу и одному пользователю. А кроме того, за директорию верхнего уровня принимается текущая рабочая директория (читать: та, из которой запущен Qt Creator).

Немного повозившись, родился патч:

Perforce-VCS-plugin-fix-top-level-directory-detection.patch
From c111318c78acb2b7ddd41533de3577fa7dc64b1d Mon Sep 17 00:00:00 2001
From: Alexander Drozdov <adrozdoff@gmail.com>
Date: Tue, 10 Sep 2013 17:33:55 +1100
Subject: [PATCH] Perforce VCS plugin: fix top-level directory detection
 
---
 src/plugins/perforce/perforcechecker.cpp        | 21 ++++++++-
 src/plugins/perforce/perforcechecker.h          |  5 ++-
 src/plugins/perforce/perforceconstants.h        |  2 +-
 src/plugins/perforce/perforceplugin.cpp         | 57 ++++++++++++++++++++-----
 src/plugins/perforce/perforceplugin.h           | 16 ++++++-
 src/plugins/perforce/perforceversioncontrol.cpp |  2 +-
 6 files changed, 86 insertions(+), 17 deletions(-)
 
diff --git a/src/plugins/perforce/perforcechecker.cpp b/src/plugins/perforce/perforcechecker.cpp
index 5971c00..b9b0395 100644
--- a/src/plugins/perforce/perforcechecker.cpp
+++ b/src/plugins/perforce/perforcechecker.cpp
@@ -28,6 +28,7 @@
 ****************************************************************************/
 
 #include "perforcechecker.h"
+#include "perforceconstants.h"
 
 #include <utils/qtcassert.h>
 #include <utils/synchronousprocess.h>
@@ -78,7 +79,8 @@ void PerforceChecker::resetOverrideCursor()
 
 void PerforceChecker::start(const QString &binary,
                             const QStringList &basicArgs,
-                            int timeoutMS)
+                            int timeoutMS,
+                            const QString &workingDirectory)
 {
     if (isRunning()) {
         emitFailed(QLatin1String("Internal error: process still running"));
@@ -91,6 +93,15 @@ void PerforceChecker::start(const QString &binary,
     m_binary = binary;
     QStringList args = basicArgs;
     args << QLatin1String("client") << QLatin1String("-o");
+
+    if (Perforce::Constants::debug)
+        qDebug() << "PerforceChecker::start: [" << workingDirectory << "]" << m_binary << args;
+
+    if (!workingDirectory.isEmpty())
+    {
+        m_process.setWorkingDirectory(workingDirectory);
+    }
+
     m_process.start(m_binary, args);
     m_process.closeWriteChannel();
     // Timeout handling
@@ -105,6 +116,11 @@ void PerforceChecker::start(const QString &binary,
     }
 }
 
+bool PerforceChecker::waitForFinished(int msec)
+{
+    return m_process.waitForFinished(msec);
+}
+
 void PerforceChecker::slotTimeOut()
 {
     if (!isRunning())
@@ -169,6 +185,9 @@ static inline QString clientRootFromOutput(const QString &in)
 
 void PerforceChecker::parseOutput(const QString &response)
 {
+    if (Perforce::Constants::debug)
+        qDebug() << "PerforceChecker::parseOutput: " << response;
+
     if (!response.contains(QLatin1String("View:")) && !response.contains(QLatin1String("//depot/"))) {
         emitFailed(tr("The client does not seem to contain any mapped files."));
         return;
diff --git a/src/plugins/perforce/perforcechecker.h b/src/plugins/perforce/perforcechecker.h
index e466250..aada848 100644
--- a/src/plugins/perforce/perforcechecker.h
+++ b/src/plugins/perforce/perforcechecker.h
@@ -50,10 +50,13 @@ public:
 public slots:
     void start(const QString &binary,
                const QStringList &basicArgs = QStringList(),
-               int timeoutMS = -1);
+               int timeoutMS = -1,
+               const QString &workingDirectory = QString());
 
     bool isRunning() const;
 
+    bool waitForFinished(int msec = -1);
+
     bool useOverideCursor() const;
     void setUseOverideCursor(bool v);
 
diff --git a/src/plugins/perforce/perforceconstants.h b/src/plugins/perforce/perforceconstants.h
index 316fc24..1f8c2a1 100644
--- a/src/plugins/perforce/perforceconstants.h
+++ b/src/plugins/perforce/perforceconstants.h
@@ -55,7 +55,7 @@ const char SUBMIT_CURRENT[] = "Perforce.SubmitCurrentLog";
 const char DIFF_SELECTED[] = "Perforce.DiffSelectedFilesInLog";
 const char SUBMIT_MIMETYPE[] = "text/vnd.qtcreator.p4.submit";
 
-enum { debug = 0 };
+enum { debug = 1 };
 
 } // Constants
 } // Perforce
diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp
index 8fd5957..1f9480d 100644
--- a/src/plugins/perforce/perforceplugin.cpp
+++ b/src/plugins/perforce/perforceplugin.cpp
@@ -824,7 +824,11 @@ bool PerforcePlugin::managesDirectory(const QString &directory, QString *topLeve
     const bool rc = managesDirectoryFstat(directory);
     if (topLevel) {
         if (rc)
+        {
+            if (Perforce::Constants::debug)
+                qDebug() << "Top Level: " << m_settings.topLevelSymLinkTarget();
             *topLevel = m_settings.topLevelSymLinkTarget();
+        }
         else
             topLevel->clear();
     }
@@ -834,28 +838,48 @@ bool PerforcePlugin::managesDirectory(const QString &directory, QString *topLeve
 bool PerforcePlugin::managesDirectoryFstat(const QString &directory)
 {
     if (!m_settings.isValid())
+    {
+        if (Perforce::Constants::debug)
+            qDebug() << "Settings invalid";
         return false;
+    }
     // Cached?
     const ManagedDirectoryCache::const_iterator cit = m_managedDirectoryCache.constFind(directory);
     if (cit != m_managedDirectoryCache.constEnd())
-        return cit.value();
+    {
+        const DirectoryCacheEntry &entry = cit.value();
+        if (Perforce::Constants::debug)
+            qDebug() << "Directory: " << directory << " is cached and managed: " << entry.isManaged;
+
+        setNewTopLevel(entry.topLevel);
+
+        return entry.isManaged;
+    }
     // Determine value and insert into cache
     bool managed = false;
     do {
         // Quick check: Must be at or below top level and not "../../other_path"
         const QStringList relativeDirArgs = m_settings.relativeToTopLevelArguments(directory);
         if (!relativeDirArgs.empty() && relativeDirArgs.front().startsWith(QLatin1String("..")))
-            break;
+        {
+            if (Perforce::Constants::debug)
+                qDebug() << "Directory " << directory << " is a relative path to current top level dir [" << relativeDirArgs << "], try find new top level.";
+            getTopLevel(directory, true);
+        }
         // Is it actually managed by perforce?
         QStringList args;
         args << QLatin1String("fstat") << QLatin1String("-m1") << perforceRelativeFileArguments(relativeDirArgs);
         const PerforceResponse result = runP4Cmd(m_settings.topLevel(), args,
                                                  RunFullySynchronous);
+
+        if (Perforce::Constants::debug)
+            qDebug() << "Perforce result:\n" << result.stdOut << "\n---\n" << result.stdErr << "\n---\n" << result.message;
+
         managed = result.stdOut.contains(QLatin1String("depotFile"))
                   || result.stdErr.contains(QLatin1String("... - no such file(s)"));
     } while (false);
 
-    m_managedDirectoryCache.insert(directory, managed);
+    m_managedDirectoryCache.insert(directory, DirectoryCacheEntry(managed, m_settings.topLevel()));
     return managed;
 }
 
@@ -1489,12 +1513,7 @@ PerforceVersionControl *PerforcePlugin::perforceVersionControl() const
 
 void PerforcePlugin::slotTopLevelFound(const QString &t)
 {
-    m_settings.setTopLevel(t);
-    const QString msg = tr("Perforce repository: %1").
-                        arg(QDir::toNativeSeparators(t));
-    VcsBase::VcsBaseOutputWindow::instance()->appendSilently(msg);
-    if (Perforce::Constants::debug)
-        qDebug() << "P4: " << t;
+    setNewTopLevel(t);
 }
 
 void PerforcePlugin::slotTopLevelFailed(const QString &errorMessage)
@@ -1504,7 +1523,7 @@ void PerforcePlugin::slotTopLevelFailed(const QString &errorMessage)
         qDebug() << errorMessage;
 }
 
-void PerforcePlugin::getTopLevel()
+void PerforcePlugin::getTopLevel(const QString &workingDirectory, bool isSync)
 {
     // Run a new checker
     if (m_settings.p4BinaryPath().isEmpty())
@@ -1514,7 +1533,23 @@ void PerforcePlugin::getTopLevel()
     connect(checker, SIGNAL(failed(QString)), checker, SLOT(deleteLater()));
     connect(checker, SIGNAL(succeeded(QString)), this, SLOT(slotTopLevelFound(QString)));
     connect(checker, SIGNAL(succeeded(QString)),checker, SLOT(deleteLater()));
-    checker->start(m_settings.p4BinaryPath(), m_settings.commonP4Arguments(QString()), 30000);
+    checker->start(m_settings.p4BinaryPath(), m_settings.commonP4Arguments(QString()), 30000, workingDirectory);
+
+    if (isSync)
+        checker->waitForFinished();
+}
+
+void PerforcePlugin::setNewTopLevel(const QString &newTopLevel)
+{
+    if (m_settings.topLevel() != newTopLevel)
+    {
+        m_settings.setTopLevel(newTopLevel);
+        const QString msg = tr("Perforce repository: %1").
+                            arg(QDir::toNativeSeparators(newTopLevel));
+        VcsBase::VcsBaseOutputWindow::instance()->appendSilently(msg);
+        if (Perforce::Constants::debug)
+            qDebug() << "P4: " << newTopLevel;
+    }
 }
 
 #ifdef WITH_TESTS
diff --git a/src/plugins/perforce/perforceplugin.h b/src/plugins/perforce/perforceplugin.h
index 8eeb1e2..8e08500 100644
--- a/src/plugins/perforce/perforceplugin.h
+++ b/src/plugins/perforce/perforceplugin.h
@@ -146,7 +146,18 @@ protected:
 
 
 private:
-    typedef QHash<QString, bool> ManagedDirectoryCache;
+    struct DirectoryCacheEntry
+    {
+        DirectoryCacheEntry(bool isManaged, const QString &topLevel)
+            : isManaged(isManaged),
+              topLevel(topLevel)
+        {}
+
+        bool    isManaged;
+        QString topLevel;
+    };
+
+    typedef QHash<QString, DirectoryCacheEntry> ManagedDirectoryCache;
 
     Core::IEditor *showOutputInEditor(const QString& title, const QString output,
                                       int editorType, const QString &source,
@@ -193,7 +204,8 @@ private:
     bool isCommitEditorOpen() const;
     QSharedPointer<Utils::TempFileSaver> createTemporaryArgumentFile(const QStringList &extraArgs,
                                                                      QString *errorString) const;
-    void getTopLevel();
+    void getTopLevel(const QString &workingDirectory = QString(), bool isSync = false);
+    void setNewTopLevel(const QString &newTopLevel);
     QString pendingChangesData();
 
     void updateCheckout(const QString &workingDir = QString(),
diff --git a/src/plugins/perforce/perforceversioncontrol.cpp b/src/plugins/perforce/perforceversioncontrol.cpp
index 19303a6..ad4f35b 100644
--- a/src/plugins/perforce/perforceversioncontrol.cpp
+++ b/src/plugins/perforce/perforceversioncontrol.cpp
@@ -178,7 +178,7 @@ bool PerforceVersionControl::managesDirectory(const QString &directory, QString
         QDebug nsp = qDebug().nospace();
         nsp << "managesDirectory" << directory << rc;
         if (topLevel)
-            nsp << topLevel;
+            nsp << *topLevel;
     }
     return rc;
 }
-- 
1.8.3.msysgit.0

// Алтай, г.Белуха

В воскресенье уже самолёт. Следить за нами можно по карте ниже, точки отсылаются при помощи трекера Delorme Inreach.

Фото с похода:

// Небольшой редизайн сайта

Собственно основу можно заметить невооружённым глазом:

  • Убрана большая шапка
  • Убраны большие закруглённые углы

Менее заметные:

  • Большой логотип претерпел некоторый «ребрендинг» (этот логотип предлагается как картинка по умолчанию при репостинге в G+)
  • Сделаны миникопии логотипа под разные размеры, один из них выводится в верхней навигационной строке, другой используется как favicon (теперь видно, что там картинка, а не чёрная клякса, но чёткости так и не получилось добиться)
  • Возвратил стандартный поиск по сайту, потому как гугловский внезапно стал глючить и выдавать пустые ответы (при этом поисковые запросы типа «site:htrd.su ЗАПРОС» работают исправно), разбираться лень, т.к. сам не веб-разработчик и тратить на это время просто жалко (на крайний случай: https://www.google.ru/search?q=site%3Ahtrd.su). Кроме того, это несколько ускорило загрузку страницы.
  • Небольшая косметика правой колонки: убрано лишнее, подкорректированы размеры шрифтов
  • Немного откорректированы шрифты заголовков

// Build Boost on Windows with MinGW

Чисто заметка, без вдавания в детали.

Для начала нужно поставить MinGW и MSYS.

Сделать это можно двумя путями. Первый, это поставить и то и другое средствами mingw-get-inst: http://sourceforge.net/projects/mingw/files/Installer/mingw-get-inst/

Но там только GCC 4.7.2, а мне нужен был GCC 4.8 (где брать свежие сборки MinGW я уже ранее писал, замечу только, что брать нужно версию с поддержкой threads-posix и dwarf, если вдруг захочется использовать бинарные сборки Qt). MSYS поставил при помощи mingw-get (http://sourceforge.net/projects/mingw/files/Installer/mingw-get/, а можно и вручную, скачивая и распаковывая файлы отсюда: http://sourceforge.net/projects/mingw/files/MSYS/). Распаковываем его, к примеру, в C:\msys, далее:

cd C:\msys\bin
mingw-get.exe update
mingw-get.exe install msys

После этого MSYS будет расположен в C:\msys\msys\1.0. Если потребуется ещё что-то от msys: mingw-get list вам в помощь.

Далее сборка Boost (у меня 1.53.0).

Распаковываем его, например в D:\boost_1_53_0

Настраиваем пути до компилятора (делаем это из запущенной копии cmd):

set PATH=c:\msys\msys\1.0\bin;c:\mingw\bin;%PATH%

Тут обращаю ваше внимание на один факт, за который разработчикам буста нужно малость по рукам настучать: буст соберётся хорошо только в случае, если MinGW поставлен в C:\MinGW и ни как иначе!

После чего собираем bjam:

cd D:\boost_1_53_0\tools\build\v2
bootstrap.bat gcc
b2 --prefix=C:\boost install
set PATH=%PATH%;C:\boost\bin

Теперь мы готовы собирать сам буст:

cd D:\boost_1_53_0\
bjam -j2 toolset=gcc --build-type=complete --prefix=C:\boost install

Вместо -j2 ставим нужное количество потоков сборки.

После продолжительной сборки буст будет расположен:

  • заголовки: C:\boost\include\boost-1_53
  • библиотеки: C:\boost\lib

И полезные параметры при сборке:

-Wno-unused-local-typedefs -DGLIBCXX_FORCE_NEW -D_WIN32_WINNT=0x0501 -DBOOST_THREAD_USE_LIB -DBOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN

Для совсем ленивых, напоминаю про альтернативную сборку MinGW от Стефана, в ней он уже обновил GCC до 4.8 и Boost до 1.53. Кстати, Стефан работает в Microsoft :-D

// С днём космонавтики!

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

// Qt Creator: C/C++ parser and "pre-included" headers

Некоторые компиляторы (если не все) поддерживают такую функциональность: через параметр командной строки можно указать файл или файлы, которые будут подключаться автоматически к каждому обрабатываемому файлу. У GCC это опция -include <file>.

В некоторых проектах используют эту особенность, как результат - явного включения файла нет, а парсер в Qt Creator'е не видит части объявлений.

Решения единого нет: для каждого типа проекта (qmake, cmake, generic & etc), теоретически, оно своё (если есть вообще). В моём случае используется Generic project, для него решение существует.

И решение достаточно простое: Generic Project Mananger использует несколько файлов для хранения настроек проекта:

  • ProjectName.creator - головной файл, по сути не содержит никакой полезной информации
  • ProjectName.files - список файлов проекта (может содержать и не исходники)
  • ProjectName.includes - пути поиска заголовочных файлов
  • ProjectName.config - как гласит комментарий внутри этого файла: «ADD PREDEFINED MACROS HERE!»

Вот последний файл самый интересный. Комментарий немного наводит в ступор и мы решаем, что тут можно только писать код вида:

#define MACRO some_value

На самом деле, парсером этот файл воспринимается как обычный заголовочный файл и информация из него используется для парсинга всего остального. Чуете профит? Если нет, подсказываю: по сути это и есть наш «pre-included» header для парсера! И писать в нём мы можем всё, что понимается препроцессором (если быть точнее: парсером скеатора). Т.е. мы можем сделать такое:

#include "includes/pre-included.h"

И всё, что объявлено в нашем pre-included.h станет доступно парсеру при обработке каждого файла. Дело сделано!

Было бы любопытно узнать как такое можно реализовать для Qmake и Cmake проектов.

PS вопрос этот я поднял в списке рассылки Qt Creator'а, пока ждал ответ, в голову пришла идея с #include, в результате список только подтвердил моё изыскание :)

UPDATE: рано обрадовался, внезапно, решение отказалось работать. Имхо, причина в несовсем корректном использовании .config файла.

// C++ Template Metaprogramming

Что-то не нашёл официального русского перевода книги, только сделанный в частном порядке (читать сложновато): http://enotcpp.blogspot.ru/2011/11/c-template-metaprogramming-david.html

На английском: http://ultra.sdk.free.fr/misc/docs/Addison.Wesley.C++.Template.Metaprogramming.Concepts.Tools.and.Techniques.from.Boost.and.Beyond.pdf или среди торрентов: http://rutracker.org/forum/viewtopic.php?t=1140883

// Binary Logic Bit Operations In C and C++

На заметку: http://www.somacon.com/p125.php там же удобный калькулятор для перевода констант между четырмя популярными системами счисления (BIN, OCT, HEX, DEC)

// Бинарные сборки MinGW

Сайт qt-project.org навёл меня на проект http://sourceforge.net/projects/mingwbuilds/files/ где можно разжиться бинарными сборками MinGW для MacOSX, Linux, Windows.

Удобдно для использования совместно с Qt Creator на Windows.

// Qt Creator: "the debugger could not load the debugging helper library" на Windows XP

Решение подсказывают тут и тут. Если коротко: нужен GDB скомпилированный с поддержкой Python и Qt Creator на это расчитывает. По первой ссылке его рекомендуют брать в QtSDK, но качать его сильно накладно. Недолгое гугление привело на эту ссылку: http://origin.releases.qt-project.org/gdb/windows-xp/.

Устанавливатся просто: скачиваем, распаковываем, в настройках китов в Qt Creator (Tool → Options… → Build & Run → Kits) выбираем новый отладчик (для MinGW) и живём.

PS другие версии: http://origin.releases.qt-project.org/gdb/ PPS более корректные ссылки: http://builds.qt-project.org/job/gdb-windowsxp/ и http://builds.qt-project.org/job/gdb-windows/

// Scott Meyers. Effective C++ in an Embedded Environment

This PDF document contains the presentation materials from Scott Meyers' two-day training course Effective C++ in an Embedded Environment. It provides an in-depth examination of how C++ can be applied in embedded systems, including costs of language features, ROMing, ISRs, memory management, safety-critical and real-time considerations, and more.

Формат: презентация в PDF, чётко и по делу.

Для желающих получить без оплаты: effectcppemb.pdf