Архив за месяц: Октябрь 2015

Мнение о книге "Сила воли. Как развить и укрепить"

 Автор книги, Келли Макгонигал, в самом начале советует читать эту книгу не более одной главы в неделю. Как прочитавший, полностью соглашусь. Ведь каждая глава содержит не только информацию, с которой надо познакомиться, но и содержит "Под микроскопом" - советы по рефлексии и "Эксперименты" - практики, которые помогут развить силу воли.
Книга написана очень живым языком, читается легко, но если не заниматься рефлексией и не применять практики, мне кажется она практически бессмыслена. Ну будешь ты знать, что Макдональдс увеличил продажи гамбургеров добавив в меню пару позиций диетического питания (салатики), а смысл? Сразу скажу, что не все под микроскопом и эксперименты я проводил. Какие-то мне не актуально, какие-то я проводил раньше и поступаю именно так, но очень много всего нового и полезного я для себя из книги почерпнул.
Нужно ли читать эту книгу? Зависит от вас. Просто читать - нет. А вот заниматься по ней, я бы рекомендовал, даже если вы считаете, что силы воли вам и так хватает.
Кстати, заканчивается книга не главными мыслями, а просьбой к читателю еще немного порефлексировать. С вашего позволения, на вопросы которые задает автор, я отвечу здесь. Т.к. этот ответ больше для себя, то пусть он будет под катом.


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

– Какой эксперимент на силу воли был вам особенно полезен?
Здесь тоже все не очень однозначно. Например, эксперимент "Укрепите свой иммунитет", я проделывал задолго до того, как книга попала ко мне в руки. Но именно благодаря этой книге, я начал регулярные медитации в рамках эксперимента "Пятиминутная медитация для тренировки мозга". Наверно, это и будет одним из самых полезных экспериментов, хотя у меня есть подозрение, что за пальму первенства с ним может посоревноваться эксперимент "Познакомьтесь  со  своим  будущим  «я»".

– Что стало для вас наибольшим откровением?
Знакомство со своим будущим  «я». Конкретно на эту особенность нашего мозга я как то не обращал внимания.

– Что вы возьмете себе на заметку?
Много чего, например, подход к подаче материала. Очень понравился. Зацепили результаты некоторых экспериментов, буду их использовать, возможно и в статьях на страницах этого блога.

Об использовании функции FormatMessage из WinAPI для расшифровки своих кодов ошибок

В WinAPI многие функции, в случае неудачного завершения своей работы, возвращают код ошибки, получить который можно при помощи функции GetLastError(). Само по себе полученное числовое значение не даёт чёткого представления о причине сбоя. Для того, чтобы понять, что же именно произошло, необходимо получить строковое сообщение, соответствующее возвращённому коду ошибки. В WinAPI существует функция FormatMessage которая, помимо заложенных в ней возможностей касающихся форматирования строк, может использоваться для получения текстового описания ошибки по её коду. Однако, использовать обозначенный механизм получения описаний ошибок можно не только для кодов системных ошибок, но так же и для кодов ошибок, определяемых вами...


Обозначенный механизм получения строкового сообщения об ошибках можно использовать в любых приложениях или программных библиотеках. Каждый EXE и DLL может содержать свой собственный набор ресурсов, определяющий локализованные варианты сообщений об ошибках. В своём программном коде можно использовать системные коды ошибок, уже определённые в составе WinAPI, в дополнение к своим кодам (дабы повторно не определять то, что уже и так имеется в системе). Для этого при вызове функции FormatMessage используется комбинация флагов FORMAT_MESSAGE_FROM_SYSTEM и FORMAT_MESSAGE_FROM_HMODULE (см. ниже комментарии в коде). Эта комбинация сообщает, что если информация об указанном коде ошибки не будет найдена в нашем модуле (DLL или EXE), то следует выполнить повторный поиск, но уже в системных ресурсах операционной системы. Т.о. в своих ресурсах можно ограничиться определением лишь того, что отсутствует в системных ресурсах. Коды системных ошибок определены в заголовке WinError.h.

Внимание!
Обозначенная выше комбинация флагов требует, чтобы в вашем модуле присутствовал ресурс с текстовыми сообщениями об ошибках. В случае его отсутствия функция FormatMessage сгенерирует ошибку с сообщением о том, что в указанном модуле отсутствуют ресурсы. Если вы используете только системные коды ошибок, то указывать флаг FORMAT_MESSAGE_FROM_HMODULE не нужно.

Формат описания текстовых файлов, содержащих локализованные сообщения об ошибках опубликован в MSDN здесь. Пример такого файла так же присутствует в MSDN. На основе сформированного текстового файла, при помощи утилиты MC.EXE генерируется набор файлов, необходимых для встраивания (в наш EXE или DLL файл) ресурсов, содержащих локализованные сообщения об ошибках.

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

Примечание
Порядок поиска локализованных ресурсов достаточно ясно изложен в описании параметра dwLanguageId функции FormatMessage.

В каталоге проекта создаём новый текстовый файл в кодировке ANSI или Unicode (т.е. UTF-16, не путать с UTF-8). Если используется Notepad++, то кодировка Unicode там обозначена как UCS-2 LE BOM.

Заполняем файл содержимым, например:

; // ***** Sample.mc *****
; // This is the header section.

MessageIdTypedef=DWORD

SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS
Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
Warning=0x2:STATUS_SEVERITY_WARNING
Error=0x3:STATUS_SEVERITY_ERROR
)

FacilityNames=(System=0x0:FACILITY_SYSTEM
Runtime=0x2:FACILITY_RUNTIME
Stubs=0x3:FACILITY_STUBS
Io=0x4:FACILITY_IO_ERROR_CODE
)

LanguageNames=(English=0x409:MSG00409)
LanguageNames=(Russian=0x419:MSG00419)

; // The following are message definitions.

MessageId=0x1
Severity=Error
Facility=Runtime
SymbolicName=MSG_BAD_COMMAND
Language=English
You have chosen an incorrect command.
.

Language=Russian
Вы выбрали неправильную команду.
.

MessageId=0x2
Severity=Warning
Facility=Io
SymbolicName=MSG_BAD_PARM1
Language=English
Cannot reconnect to the server.
.

Language=Russian
Не удаётся подключиться к серверу.
.

MessageId=0x3
Severity=Success
Facility=System
SymbolicName=MSG_STRIKE_ANY_KEY
Language=English
Press any key to continue . . . %0
.

Language=Russian
Нажмите любую клавишу для продолжения . . . %0
.

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

В меню Все Программы -> Visual Studio 2013 -> Visual Studio Tools открываем консоль Visual Studio: VS2013 x64 Cross Tools Command Prompt. Переходим в каталог проекта и запускаем программу MC.EXE с соответствующим набором опций:

  • Если содержимое текстового файла использует кодировку ANSI:
    mc.exe -a sample.mc
  • Если содержимое текстового файла использует кодировку UTF-16:
    mc.exe -u sample.mc
В результате работы обозначенной выше команды, в каталоге проекта появятся новые файлы:
  • MSG00409.bin
  • MSG00419.bin
  • Sample.h
  • Sample.rc
Добавляем в наш проект заголовочный файл Sample.h и ресурсный файл Sample.rc. Сгенерированный утилитой MC.EXE заголовочный файл выглядит следующим образом:

 // ***** Sample.mc *****
 // This is the header section.
 // The following are message definitions.
//
//  Values are 32 bit values laid out as follows:
//
//   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
//   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
//  +---+-+-+-----------------------+-------------------------------+
//  |Sev|C|R|     Facility          |               Code            |
//  +---+-+-+-----------------------+-------------------------------+
//
//  where
//
//      Sev - is the severity code
//
//          00 - Success
//          01 - Informational
//          10 - Warning
//          11 - Error
//
//      C - is the Customer code flag
//
//      R - is a reserved bit
//
//      Facility - is the facility code
//
//      Code - is the facility's status code
//
//
// Define the facility codes
//
#define FACILITY_SYSTEM                  0x0
#define FACILITY_STUBS                   0x3
#define FACILITY_RUNTIME                 0x2
#define FACILITY_IO_ERROR_CODE           0x4


//
// Define the severity codes
//
#define STATUS_SEVERITY_WARNING          0x2
#define STATUS_SEVERITY_SUCCESS          0x0
#define STATUS_SEVERITY_INFORMATIONAL    0x1
#define STATUS_SEVERITY_ERROR            0x3


//
// MessageId: MSG_BAD_COMMAND
//
// MessageText:
//
// You have chosen an incorrect command.
//
#define MSG_BAD_COMMAND                  ((DWORD)0xC0020001L)

//
// MessageId: MSG_BAD_PARM1
//
// MessageText:
//
// Cannot reconnect to the server.
//
#define MSG_BAD_PARM1                    ((DWORD)0x80040002L)

//
// MessageId: MSG_STRIKE_ANY_KEY
//
// MessageText:
//
// Press any key to continue . . . %0
//
#define MSG_STRIKE_ANY_KEY               ((DWORD)0x00000003L)


Подключаем заголовочный файл Sample.h в коде исходников и используем его. В обозначенном ниже примере мы определяем функцию isValidCommandIndex, использующую "родной" механизм WinAPI для оповещения о возникновении ошибок:

#include<Windows.h>
#include <iostream>
#include "Sample.h"
using namespace std;
/*
MSDN resources:

FormatMessage function:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351%28v=vs.85%29.aspx

Message Text Files:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd996906%28v=vs.85%29.aspx

Sample Message Text File:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd996907%28v=vs.85%29.aspx

Message Compiler (MC.exe):
https://msdn.microsoft.com/en-us/library/windows/desktop/aa385638%28v=vs.85%29.aspx

*/

// Our function uses the WinAPI mechanism for notifying of error
BOOL isValidCommandIndex(int index){
  if (index < 0){
    SetLastError(MSG_BAD_COMMAND);  // the identifier from the Sample.h
    return FALSE;
  }
  else{
    SetLastError(ERROR_SUCCESS);
    return TRUE;
  }
}

int wmain(int argc, TCHAR* argv[])
{
  // Getting the readable Cyrillic chars in the console window for ANSI and 
  // Unicode encodings...
  setlocale(LC_ALL, "Russian");
  
  int command_index = -1;
  BOOL result = isValidCommandIndex(command_index);
  if (!result){    
    DWORD errCode = GetLastError(); // Get the last error at once

    LCID langId = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
    // Also you can try such variants, for getting the messages with other 
    // localizations:
    // LCID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
    // LCID langId = MAKELANGID(LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA);

    PTCHAR message = NULL;

    // HANDLE of EXE or DLL which contains the resource with the error messages
    // which we are to get. In our case this is current EXE, therefore it is
    // possible to point the NULL value of HANDLE for the FormatMessage 
    // function.
    HANDLE handle = NULL;

    int tchars_count = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
      FORMAT_MESSAGE_FROM_SYSTEM | /* Search in the system resources if the
                                   message will not be found in our module. It
                                   allows to use the system error codes in our
                                   code additionally to defined by us error
                                   codes. */
     FORMAT_MESSAGE_FROM_HMODULE |
     FORMAT_MESSAGE_IGNORE_INSERTS, handle, errCode, langId, (PTCHAR)&message,
     0, NULL);
    if (0 == tchars_count){
      // In the Watch[1-4] window it is possible to get the last error code 
      // through the '$err,hr' (without quotes) name. Add this name into the 
      // Watch[1-4] window if you need.
      DWORD lastErrorCode = GetLastError();
      if (lastErrorCode != ERROR_SUCCESS){
        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
          FORMAT_MESSAGE_FROM_SYSTEM |
          FORMAT_MESSAGE_IGNORE_INSERTS, NULL, lastErrorCode, langId,
          (PTCHAR)&message, 0, NULL);
      }
    }
    wcout << message;
    LocalFree(message);
  }  
  // *******************************************
  wchar_t c;
  wcout << L"Нажмите любую клавишу для выхода..." << endl;
  wcin >> c;
  return 0;
}

Компилируем наш код и запускаем его. В консоли получаем следующий вывод:

Вы выбрали неправильную команду.
Нажмите любую клавишу для выхода...

Если указать английскую локализацию (см. комментарии в коде), то сообщение об ошибке будет на английском:

You have chosen an incorrect command.
Нажмите любую клавишу для выхода...

Как видим, текст сообщения об ошибке соответствует тому, который мы определили в составе ресурсов нашего EXE файла.

Где это может пригодиться?
Например, если созданные вами функции могут использоваться сторонними разработчиками, имеющими опыт работы сWinAPI, то задействование стандартного механизма оповещения об ошибках, предоставляемого операционной системой Windows, для них будет делом привычным. Вам достаточно будет лишь сообщить в документации о том, что для получения кода ошибки и его расшифровки следует использовать стандартный механизм WinAPI: функции GetLastError и FormatMessage.

Устанавливаем, настраиваем и начинаем работаь с Git

Так получилось, что возникла потребность в познакомиться с Git. Вот здесь есть учебник по Git, который я и читаю. В этой и, возможно, паре ближайших статей будет выжимка для "себя", того как и что делать. У меня есть подозрение, что это будет мало кому интересно... Лучше читать указанный выше учебник, но мало ли, кому еще пригодится.

Установка
Скачать последнюю версию дистрибутива для Windows можно здесь. Ставил в режиме далее-далее-далее. Если будут какие то особенности, то потом допишу.

Настройка
Прописать имя пользователя и почту в настройки пользователя:
$ git config --global user.name "Alexey Losev"
$ git config --global user.email myemail@domen.ru
Кроме --global (настройки текущего пользователя), есть еще --system (системные настройки) и без ключа, это значит настройки текущего репозитария.
Проверить что все записалось нормально, можно командами:
$ git config --global user.email
$ git config --global user.name
Или даже:
$ git config user.email
$ git config user.name
Ну или все настройки доступны командой:
$ git config --list

Справка
Получить справку по команде можно командами:
$ git config --global user.email
$ git config --global user.name
Справка выполнена в виде html, которые при установке сохраняются на диск и доступна без подключения к интернету.
Кстати, команда:
$ man git-<команда>
В Windows не работает.

Создание репозитория
Для путешествия по папкам через Git Bush можно пользоваться стандартными досовскими командами (cd, dir). Только вот есть пара отличий:
1. При переходе на другой диск необходимо вместо d:/ писать /d/
2. Восклицательный знак в пути - это проблема
Ну а так, все стандартно:
$ cd /d/git/robotsbattle
$ dir

Все, создаем репозиторий:
$ git init
Для добавления в репозиторий существующих файлов можно воспользоваться командой:
$ git add *.sln
Фиксация изменений происходит командой
$ git commit -m 'комментарий к коммиту'
Получение того, что у нас твориться в репозитории:
$ git status
Чтобы посмотреть не просто список, а что изменилось в файлах, можно вызвать:
$ git diff
Получим аналог Create Patch из SVN. Пример как это работает:
У команды git diff, есть модификация:
$ git diff --cached
Которая позволяет понять одну магию. В коммит попадают только проиндексированные файлы. Т.е. если файл изменился, то для того, чтобы он попал в коммит его необходимо проиндексировать командой 
add:
$ git add RobotsBattle/Cell.cs
И здесь есть тонкость, хотя Windows игнорирует регистр символов, а вот Git Bash - нет. Т.е. предыдущая команда отработает корректно, а вот эта нет:
$ git add robotsbattle/cell.cs
После добавления файла в кэш, git diff без ключей его игнорирует, а вот указанный ключ 
--cached позволяет посмотреть, что же мы закешировали.
Если заниматься индексацией каждый раз не хочется, то можно вызвать коммит для всех измененных файлов не зависимо от того, закешированы они или нет следующей командой:
$ git commit -a -m "Добавлен комментарий"
Ну и так как у нас в папках проектов всегда есть файлы, которые добавлять в хранилище не надо, то можно создать файл с расширением  .gitignore 
К шаблонам в файле .gitignore применяются следующие правила:
  • Пустые строки, а также строки, начинающиеся с #, игнорируются.
  • Можно использовать стандартные glob-шаблоны.
  • Можно заканчивать шаблон символом слэша (/) для указания каталога.
  • Можно инвертировать шаблон, использовав восклицательный знак (!) в качестве первого символа.
Вот так может выглядеть этот файл, чтобы игнорировать файлы и папки начинающиеся с точки, а также папке bin и obj в первом уровне вложенности относительно корня:

Glob — шаблоны в .gitignore

Для определения какие файлы в папке должны игнорироваться git-ом, создается файл .gitignore. В котором применяются glob - шаблоны. То что под катом, это краткая дока по glob-шаблонам для тех, кто не работает в *nix системах. Т.е. для меня.

Начну с того, что строка может содержать имя файла или директории. В этом случае шаблоном она являться не будет. Например, если у меня в папке с решением лежит папка .vs, то я могу в файле .gitignore прямо так и написать .vs. И эта папка будет игнорироваться.
Glob шаблоном является строка содержащая один из символов "?", "*" или "[".
"?", "*" пока они не в квадратных скобках работают весьма привычно. "?" - любой символ, "*" - любая последовательность символов. А вот квадратные скобки задают классы символов.
Класс символов позволяет задать что на этой позиции будет находится символ принадлежащий классу или (если после открывающейся скобки идет восклицательный знак "!") не принадлежащий классу.
Классы задаются перечислением, либо диапазонами.
[abc] - любой из символов a, b, c.
[a-c] - любой из символов находящихся между a и c. Т.е. те же три символа a, b, c.
[a-c1-3] - любой из символов a, b, c или цифра от 1 до 3.
[!abc] - любой символ кроме букв a, b, c.
Если в класс должны входить закрывающаяся скобка "]", то она должна идти первой в классе:
[]a-c] - закрывающаяся скобка или любой из символов a, b, c.
Если в классе необходимо использовать "-" именно как символ, то он должен стоять на первой или последней позиции.
[]-] - соответствует двум символам: "]" и "-"
[--/] - соответствует  трем символами: "-", "." и "/".
Ну и пара примеров.
Игнорируем все что начинается с точки (файлы и папки):
В папках RobotsBattle и RobotsBattleConsole есть папки bin и debug. Мне эти папки надо исключить: