Тема статьи - конвертация mp3-тегов, созданных в кодировке windows-1251, в кодировку utf-8, под управлением операционной системы Linux.

В чем проблема

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

Дома у меня имеются только две операционные системы - Mac OS X 10.10 и Linux Mint 17 Cinnamon. И вот тут возникает небольшая проблема, связанная с тем, что Audacious под Linux и iTunes под Mac не отображают правильно мета-информацию проигрываемых mp3-файлов аудио-книг, если эти файлы созданы под Windows.

Другими словами, аудио-проигрыватель “читает” аудио-книгу, но вот понять визуально - какую, нельзя. Не видно названия книги, ее автора, имени чтеца. Происходит это потому, что оба вышеназванных проигрывателя не могут правильно отображать мета-данные mp3-файлов, если эти мета-данные созданы в кодировке windows-1251.

Как решить проблему

Решением вопроса является перекодировка мета-данных mp3-файлов, перевод символов из кодировки windows-1251 в кодировку utf-8, с которой умеют работать Audacious и iTunes.

Решение оказалось на удивление простое и “под рукой”. Популярный редактор mp3-тегов под Linux с названием EasyTAG в два счета справляется с задачей. Главное - нужно правильно настроить чтение mp3-тегов этой программой.

Последовательность действий по настройке EasyTAG

  1. Устанавливаем программу EasyTAG

  2. Переходим в настройки программы EasyTAG - “Edit - Preferences”

  3. К окне настроек программы EasyTAG переходим на вкладку “ID3 Tag Settings”

  4. Устанавливаем параметры программы EasyTAG так, как это показано на скриншоте:

Параметры программы EasyTAG

Если описать двумя словами, то необходимо для “ID3v1 tags” выбрать кодировку Windows-1251, для “ID3v1 tags” выбрать кодировку utf-8. Для поля “Character Set for reading ID3 tags” также выбрать кодировку windows-1251.

Конвертация в программе EasyTAG

Когда программа EasyTAG настроена, то процесс конвертации mp3-тегов из кодировки windows-1251 в кодировку utf-8 выполнить проще простого.

  1. Открываем в программе EasyTAG папку с коллекцией mp3-файлов, которые необходимо обработать (переконвертировать).

  2. Выделяем в окне программы EasyTAG все эти файлы.

  3. Сохраняем их.

Да, именно так - “открыл-сохранил”, ничего больше. И теперь Audacious вместе с iTunes прекрасно читают обработанные файлы музыки (и аудио-книг).

На этом все.


О чем будет речь? О миксинах библиотеки Nib. Ранее я уже писал о том, как подключать эту библиотеку в свой проект. Ничего сложного в этом нет - достаточно установить Nib и подключить ее в проект.

Но вот вопрос о миксинах этой библиотеки - это отдельный вопрос. Дело в двух моментах - размере библиотеки и документации к ней.

Во-первых - Nib гораздо меньше, чем Compass (это чтобы было, с чем сравнивать). Compass больше, тщательнее сработан - в этой библиотеке есть миксины практически на все случаи жизни. У Nib миксинов меньше, ощутимо меньше.

На это можно ответить вполне резонно. Первое - из личного опыта, на своей практике из всего большого многообразия миксинов Compass я использовал только 10 штук (максимум). Второе - написать миксин на Stylus не просто, а очень просто! Так что, если возникает в этом необходимость - никаких проблем в создании пользовательского миксина не может быть.

Вторая проблема с Nib более существена и неприятна, скажем так. Заключается она в отсутствии хорошо сделанной документации к библиотеке Nib. То есть, есть официальный сайт проекта Nib, есть репозиторий на GitHub. Но вот такой хорошо оформленной документации, как у Compass, вы не найдете.

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

Миксин Size

Миксин для задания размеров элементам

1
display: block
или
1
display: inline-block
. Преимущество у данного миксина - в краткости его написания. Не нужно писать -
1
width: 20px; height: 20px;
, достаточно написать одну строчку:

.block
  size 20px 30px
.block
  width: 20px;
  height: 30px;
.block
  size 20px
.block
  width: 20px;
  height: 20px;

Миксин Overflow

Миксин для задания свойства

1
text-overflow: ellipsis
. Полезный миксин, которые реально может помочь в написании одной строки стилей вместо трех правил:

.block
  overflow ellipsis
.block
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;

Миксин Absolute/Fixed/Relative

Миксин для генерирования CSS-свойства

1
position: absolute
,
1
position: fixed
или
1
position: relative
. Этот миксин очень похож на миксин
1
size
- все преимущество его использования только в краткости записи:

.block
  absolute top left
position: absolute;
top: 0;
left: 0;
.block
  absolute top 20px left 30px
.block
  position: absolute;
  top: 20px;
  left: 30px;
.block
  absolute bottom 20px right 30px
.block
  position: absolute;
  bottom: 20px;
  right: 30px;
.block
  relative top 10px left 20px
.block
  position: relative;
  top: 10px;
  left: 20px;
.block
  fixed top 10px left 2%
.block
  position: fixed;
  top: 10px;
  left: 20px;

Миксин Border

Миксин для генерирования CSS

1
border: 1px solid color
. Достаточно бесполезный миксин, так как проще и быстрее воспользоваться shortcut’ом
1
bd+
из Emmet.

.block
  border #800
.block
  border: 1px solid #800

Миксин Clearfix()

Миксин для генерации

1
clearfix
. У
1
jeet.gs
есть свой миксин
1
cf()
для генерации
1
clearfix
. Однако, миксин
1
clearfix()
имеет более понятное название, говорящее - что этот миксин делает. Поэтому использование этого миксина более логичное - читая код, можно сразу сказать, что этот миксин делает.

Функция rgba()

Если быть точным, функция

1
rgba()
не относится к миксинам библиотеки Nib. Это функция препроцессора Stylus. И задача ее - преобразование значения цвета в формате HEX в формат RGBA(). Достаточно бесполезная функция, если только кодер не привык писать значения цветов в RGBA-формате:

.block
  color rgba(#ff0000, .8)
.block
  color: rgba(255, 0, 0, 0.9);

Миксин Background

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

1
top
,
1
left
,
1
right
,
1
bottom
:

.block
  background linear-gradient(top,#f00,#0f0)

Миксин для генерации радиального градиента - очень похож на линейный градиент. Разница только в некоторых моментах:

.block
  background radial-gradient(center,#f00 30%, #fff 31%)

Миксин Box-sizing

Еще один полезный миксин - для генерации CSS-свойства

1
box-sizing: border-box
. Что это за свойство, говорить не приходиться:

.block
  box-sizing: border-box
.block {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

Миксин Image

Миксин для генерации CSS-свойства

1
background-image
. Генерируются два свойства - для нормального разрешения и для дисплеев Retina. Для этого необходимо подготовить два варианта изображений как было сказано выше - тогда миксин сработает.

Первое изображение - нормального размера для нормального разрешения. Второе изображение - увеличенная вдвое версия нормального изображения, для Retina-экранов (это версия

1
@2x
):

.block
  image 'images/background.jpg'
.block {
  background-image: url("images/background.jpg");
}

@media all and (-webkit-min-device-pixel-ratio: 1.5) {
  .block {
    background-image: url("images/background@2x.jpg");
    background-size: auto auto;
  }
}

На этом все.


К вопросу о типах форм в HTML5, регулярных выражениях и валидации форм на основе регулярных выражений. Философское рассуждение на ночь глядя.

Атрибут required

Наиболее простой способ реализации валидации html-форм - это добавить к

1
input(type="text")
атрибут
1
required
.

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

Заметьте - браузеры сами будут это выполнять, без какого-либо участия Javascript/jQuery с нашей стороны (это и есть одна из многогранных сторон HTML5).

В CSS3 для форм ввода разработаны два псевдо-класса:

  • :valid
  • :invalid

Оба псевдокласса предназначены для управления видом форм (

1
border
,
1
background
, помещения маркеров внутрь или снаружи формы) в случае валидности или невалидности содержимого этой формы.

Например, такой простейший код будет изменять фон поля ввода при валидности или невалидности содержимого:

&__input
  border 1px solid #ddd
  border-radius 5px
  padding 3px 10px

  &:valid
    background-color rgba(245,255,250,.5)

  &:invalid
    background-color rgba(220,20,60,.5)

Тут возникает законный вопрос - а каким образом браузер определяет, валидное или невалидное содержимое у этого поля?

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

1
:invalid
.

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

1
:valid
.

Note! Содержимое атрибута

1
placeholder
не рассматривается браузером как содержимое формы. Другими словами, если поле ввода имеет атрибут
1
placeholder
с каким-то значением, то это поле будет считаться браузером все равно невалидным.

Типы input

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

Одним из таких способов фильтрации введенных данных является задание для элемента

1
input
его типа. Это также одна из “фишек” HTML5 и заключается она в том, что для поля ввода
1
input
можно указать, какого типа данные ожидаются в нем.

Например,

1
input(type=“email”)
говорит о том, что в это поле нужно вводить только адреса электронной почты;
1
input(type=“number”)
- только числа;
1
input(type=“tel”)
- только номера телефонов;
1
input(type=“date”)
- только дату;
1
input(type=“url”)
- только URL-адреса; и так далее.

Краткий список HTML5-типов

1
input
’ов:

  • email
  • number
  • tel
  • date
  • url
  • time
  • week
  • color
  • search

Эти различные типы input’ов в HTML5 - не просто блаж в угоду призрачной HTML-семантики, как я сам воспринимал их ранее. На самом деле - это именованные регулярные выражения.

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

Грубо говоря -

1
[1,2,3,4,5,6,7,8,9]
- это уже регулярное выражение. Если этому регулярному выражению присвоить имя
1
number
, то получится именованное регулярное выражение
1
number
.

Фактически типы

1
input
’ов, которые были рассмотрены выше - это именованные регулярные выражения, предустановленные разработчиками HTML5\браузеров.

И когда для элемента

1
input
устанавливается тип
1
type="email"
(к примеру), то этим фактом браузеру всего лишь указывается предустановленное регулярное выражение, которое браузер должен будет использовать при проверке введенных данных.

Вот я и подошел к самому интересному моменту - для чего нужны регулярные выражения? А нужны они для проверки введенных данных. Это маска, которую браузер накладывает на введенные пользователем данные. Совпала маска и данные - данные валидные; не совпала маска и введенные данные - данные невалидные.

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

Подключаются пользовательские регулярные выражения в HTML с помощью атрибута

1
pattern
и выглядит это таким образом (регулярное выражение для проверки IPv4-адреса):

input type="text" pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"

Note! Использование пользовательского

1
pattern
совместно с любым HTML5-типом (email, date, range, tel, number и так далее) для элемента input почти никогда не имеет смысла по определению.

На этом все.


Обширная и достаточно сложная тема. Однако необходимая, если стоит задача изучить и иметь возможность работать в Git.

Эта тема касается отмены изменений в Git. Так как эта система контроля версий представляет из себя три ветки - рабочая директория, буфер, репозиторий - то будут рассмотрены все три способа.

Отмена изменений в рабочей директории

Для отмены изменений в рабочей директории необходимо выполнить одну команду:

git checkout -- name_of_file

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

Обязательным условием использования команды checkout является двойной дефис. Это “говорит” команде checkout, что в данном случае нужно оставаться в текущей ветке (branche).

Отмена изменений в буфере

Для отмены изменений в буфере нужно использовать команду:

git reset HEAD name_of_file

Эта команда “вернет” файл name_of_file из буфера в рабочую директорию.

Отмена изменений в репозитории

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

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

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

Как же поступить в данной ситуации?

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

Опция amend

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

Соответственно, раз у этого коммита нет потомков, то изменение этого коммита не повлечет за собой нарушение целостности всей цепочки коммитов. Измениться только этот коммит - и только.

Изменить крайний коммит можно просто перезаписав его. Для этой цели служит ключ –amend. Команда в целом представляет из себя следующее:

git commit --amend -m "Add some commit"

Как только будет выполнена подобная команда, крайний коммит (тот, на котором находится указатель HEAD) будет перезаписан и это очень легко проследить - достаточно сравнить контрольную сумму SHA этого коммита до и после изменений.

Команда checkout

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

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

Команда checkout может заставить указатель HEAD вернуться назад, на предыдущее место остановки - на предыдущий коммит. И необязательно этот коммит должен быть предыдущим - он может быть любым более ранним.

Все что для этого нужно - это указать тот коммит, к которому должен вернуться HEAD. Указать коммит просто - у каждого коммита есть уникальный идентификатор - контрольная SHA-сумма.

Команда возврата к нужному коммиту выглядит таким образом:

git checkout -- 4a2f59a32bd1074c42 name_of_file

Можно указать только часть SHA-суммы, так как это показано выше.

И тогда Git произведет сброс состояния (которые были сделаны в последнем коммите) файла name_of_file в буфер. Если ввести команду git status то увидим, что в буфере будут изменения, готовые для коммита. Это те самые изменения файла name_of_file, которые мы “выбросили” из репозитория.

Дальше выполняем “выброс” изменений файла name_of_file из буфера в рабочую директорию, чтобы мы смогли внести правки в этот файл:

git reset HEAD name_of_file

Все, что будет внесено в этот файл, а затем закоммичено - будет иметь уже другую контрольную сумму. А следовательно - это уже будет совсем другой коммит.

Зеркалирование коммитов

Одной из разнообразных команд Git для внесения изменений в репозиторий является команда revert.

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

Синтаксис команды revert также прост:

git revert 4a2f59a32bd1074c42

где 4a2f59a32bd1074c42 - это часть SHA-суммы крайнего коммита.

Команда reset

Команда reset также может изменять репозиторий Git. Делает она это путем смещения указателя HEAD на нужный коммит.

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

Ситуация очень похожа на то образное сравнение цепочки коммитов Git с магнитофонной лентой. Стоит отмотать ленту на 10-20 минут назад и снова начать запись, то все более поздние записи (относительно этого места) будут перезаписаны.

У команды reset есть три ключа, которые незначительно видоизменяют ее работу:

  • -soft
  • -mixed
  • -hard

Команда git reset –soft 4a2f59a32bd1074c42 произведет смещение указателя HEAD на указанный коммит 4a2f59a32bd1074c42. При этом Git произведет сброс изменений в буфер. В результате буфер и рабочая директория будут идентичными между собой; а репозиторий будет переведен в более ранее состояние.

Команда git reset –mixd 4a2f59a32bd1074c42 аналогична предыдущей. Также будет произведено смещение указателя HEAD. Но теперь Git сбросит изменения в рабочую директорию. Репозиторий и буфер будут идентичными друг другу и находиться в более раннем состоянии.

Команда git reset –hard 4a2f59a32bd1074c42 самая “жесткая”. Также будет произведено смещение указателя HEAD на указанный коммит, но при этом будет произведен сброс всех трех деревьев Git - репозитория, буфера и рабочей директории. Все три будут идентичными друг другу.

Команда clean

В системе Git существует команда clean для удаления не отслеживаемых файлов в рабочей директории.

Разница между командой git rm и clean заключается в том, что при удалении файлов из рабочей директории первой командой они вроде как удаляются. Но на самом деле удаленные файлы все еще остаются в системе Git. Просто они помещены в раздел мусора и являются теперь мусором.

Команда clean как раз и выполняет очистку мусора в системе. Она удаляет все не отслеживаемые и неиспользуемые файлы.

Но даже это она делает очень осторожно. Если просто запустить git clean, то ничего не произойдет. Система Git скажет, что команду clean необходимо запускать либо с ключом -n, либо с ключом -f.

Запуск git clean -n - это тестовый запуск команды удаления. Ничего удалено не будет - система лишь покажет, что она собирается удалить, какие файлы.

А вот запуск git clean -f произведен реальное удаление всех файлов, которые Git считает мусором. И в этом случае эти файлы будут потеряны навсегда.

На этом все.


Два способа игнорирования файлов - локальный и глобальный. Шаблоны для игнорирования файлов в для различных операционных систем, языков программирования, CMS и т. д. Игнорирование уже отслеживаемого файла в Git. Отслеживание пустых директорий.

Шаблоны правил для .gitignore

Два ресурса на GitHub, в которых собраны шаблоны файла

1
.gitignore
для разных случаев - разных операционных систем, разных языков программирования и т. д.

Общий список правил

По ссылке ниже представлен набор общих правил и рекомендаций при создании файла

1
.gitignore
. Помимо этого, в данном разделе показан шаблон для самого общего случая использования
1
.gitignore
:

Общий список правил игнорирования файлов в Git

Детализированный список правил

По ссылке ниже представлен более детальный и полезный список правил, по которым создается файл

1
.gitignore
. В этом списке можно найти рекомендации для разных операционных систем (Linux, Mac OS X, Windows, Android), разных языков программирования (Java, Perl и т. д.), различных CMS (к примеру - Joomla, Magento, Jekyll). Даже для README есть свой набор правил!

Деталированный список правил игнорирования файлов в Git

Помимо списка языков программирования, в котором для каждого пункта этого списка представлены рекомендованные правила для файла

1
.gitignore
, имеется еще дополнительная директория “Global”.

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

Глобальное игнорирование

В Git возможно игнорирование файлов двумя способами:

  • локально
  • глобально

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

Ярким примером такого глобального игнорирования являются служебные файлы операционной системы - они должны игнорироваться всегда и в любом проекте Git.

Файл конфигурации с глобальным игнорированием может быть назван как угодно (в отличие от файла

1
.gitignore
). Главное - он должен располагаться в домашней директории пользователя, а не в директории с проектом. И это его главное отличие от файла
1
.gitignore
.

После того, как файл глобального игнорирования создан, необходимо добавить его в конфигурационный файл Git. То есть, “сказать” Git, что “у тебя есть список файлов, которые ты должен игнорировать; этот список называется так и расположен он здесь”.

Выполняется это командой:

git config --global core.excludesfile ~/.gitignore_global

Если теперь взглянуть на конфигурационный файл Git, то увидим следующее:

$ cat ~/.gitconfig
[user]
    name = g*e
    email = g*e@gmail.com
[core]
    excludesfile = /Users/g*e/.gitignore_global

Игнорирование отслеживаемого файла

Может возникнуть ситуация, когда файл был создан и помещен в репозиторий Git. То есть, теперь он является отслеживаемым.

Но это была ошибка - этот файл не нужно было отслеживать! Как сказать Git, чтобы он не отслеживал этот файл?

Для этого нужно выполнить два шага.

Первый - это внести имя нужного файла в список игнорируемых файлов - отредактировать файл

1
.gitignore
.

Однако, этот шаг еще ничего не даст - Git все также будет его отслеживать, так как он уже внесен в буфера обмена.

Для этого нужно “вынуть” данный файл из буфера обмена. Это выполняется командой:

git rm --cached name_of_file

Данная команда удалит указанный файл из буфера обмена, однако оставит в рабочей директории и в репозитории. Последующий коммит произведет удаление этого файла и из репозитория.

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

Все последующие изменения в этом файле отслеживаться не будут.

Отслеживание пустых директорий

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

Заключается он в том, что Git - это система контроля версий для файлов! Другими словами - Git умеет отслеживать только файлы!

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

Кстати сказать, я сам когда-то был таким новичком и столкнулся с этим непонятным для меня фактом. Интуитивно догадался, в чем дело и поступал таким “корявым” (как я считал) способом.

К примеру, для директории psd я создавал файл-заглушку

1
dummy.psd
размером 1px*1px. Главное - чтобы в директории psd что-то лежало - тогда Git не удалит ее! )

Как оказалось, я был прав! И это единственный правильный способ заставить Git отслеживать пустые директории.

Одна только маленькая поправка - в мире Unix такой файл-заглушку можно создать с помощью команды

1
touch
и выглядеть такой файл будет так (общепринятое соглашение):

.gitkeep

Что же - этот способ более аккуратный и грамотный!

На этом все.