2016-01-23

О BTSync

На HappyDev я заюзал BitTorrent Sync для раздачи материалов мастер-классов. В основном это были образы виртуальных машин, т.е. относительно большие файлы. И BTSync показал себя неплохо.
BTSync
Конечно, можно было бы сложить эти гигабайты куда-нибудь в Dropbox или даже Google Drive. Но в моём Дропбоксе совсем нет сотни гигабайт, а платить $9.99/month за Pro версию что-то не хочется. В Google Drive сотенка гигов даётся за $1.99/month, тоже не хочется.
Но проблема даже не столько в цене. Качать из облаков — медленно. И чтобы качать из облаков, нужен хороший интернет. А очень хотелось иметь возможность раздавать файло и без интернетов, в локалке, на месте проведения конференции. И BTSync это может. Проверяли, в 100Мбитной локалке может раздавать на полных 10Мбайтах в секунду.
Случились, конечно, некоторые косяки, которые к самому BTSync отношения не имеют. Надо было раздавать образы и только образы, но не инсталляторы всяких виртуалбоксов. Чтобы раздавать по локалке, нужна локалка, а зафигачить вайфай по всей базе отдыха оказалось выше наших возможностей :)
No Inet
BitTorrent Sync — проприетарная программа. Поэтому вы не найдёте её в репозиториях той же Убунты. Придётся, in offtopic way, качать с официального сайта. Если под Windows и Mac у BitTorrent Sync есть нормальный GUI, то для Linux у крайних актуальных версий 2.x есть только веб интерфейс. Качаете, распаковываете, запускаете btsync, заходите на http://localhost:8888 и, при первом запуске, задаёте пароль для доступа к интерфейсу.
В отсутствии GUI есть своё преимущество. Можно без проблем водрузить это дело на какой-нибудь сервер. Только придётся нарисовать Systemd Unit или init скрипт. Ну и создать конфиг на JSON.
BitTorrent
Что такое BitTorrent, надеюсь, объяснять не надо. Мы посредством этого протокола скачиваем большие популярные файлы или даже кучки файлов. Подразумевается, что некий доброжелатель подготавливает эти файлы, формирует .torrent файл, где описаны контрольные суммы кусков-сегментов этих самых файлов, и организует раздачу через некоторый трекер. Желающие скачать файлы скачивают себе .torrent файл, BitTorrent клиент подключается к трекеру, узнаёт, где находятся сегменты файлов (первоначально — только на компьютере организатора раздачи, потом — на куче компьютеров участников раздачи), подключается к этим компьютерам и обменивается кусками файлов. Это P2P обмен, трафик идёт не между сервером и клиентами (как в облаке), а между всеми клиентами, которые равнозначны. Трекер нужен только для того, чтобы клиенты могли найти друг друга. И есть другие протоколы поиска, которые прекрасно работают без трекера, и, в том числе, в локальной сети.
BitTorrent Sync — это такой BitTorrent для ленивых, для локального использования. С помощью BTSync тоже децентрализованно раздаются папки с файлами (только папки). Но нет нужды заниматься генерацией .torrent файла или заниматься публикацией на трекере. Всё это BTSync берёт на себя. К тому же, в любой момент можно поменять содержимое папки, и изменённые файлы будут дополнительно розданы клиентам, а удалённые — удалены. В классическом BitTorrent для этого надо создать новый .torrent файл, фактически начать раздавать новый набор файлов, и попросить всех клиентов перезапустить раздачу.
Folder link
Берём файлы, которые нужно раздать. Складываем их в одну папочку. Добавляем папку в BTSync. В бесплатном варианте доступен только тип папки Standard. Ну и всё, раздача готова. Ну ещё, пожалуй, надо бы открыть несколько портов и иметь реальный IP, если собираетесь раздавать в интернеты.
Теперь нужно дать доступ к раздаваемым файлам всем желающим и только им. Тут есть два способа. Можно раздать ключ. Для каждой папки есть два ключа: Read Only и Read & Write. По первому ключу можно только получать файлы папки, но не менять содержимое папки. По второму ключу можно делать с файлами в папке что угодно, будет происходить всесторонняя синхронизация всех произведённых изменений. Ключ выглядит как строка в 33 ASCII символа.
Другой способ — ссылка. Ссылка ведёт на сайт link.getsync.com, где объясняется, что это такое, и имеется кнопочка для скачивания BitTorrent Sync, что, безусловно, удобно для выкладывания где угодно без подробного объяснения, что такое есть BTSync. Ссылка бывает тоже только на чтение или на чтение и запись. В ссылке содержится имя папки, что очень удобно. Ссылка может протухать, т.е. имеет ограниченное время действия. Ссылка может иметь ограничение на количество использований, так можно ограничить количество тех, кому вы раздаёте файлы. А ещё ссылка должна подтверждаться на том компьютере, где она выдана. Т.е. вы можете видеть каждого, кто хочеть забрать файлы, и решить: этому давать, а этому — не давать.
Даже если вы сняли галочку явного подтверждения для ссылки, все вновь подключаемые клиенты должны связаться с компьютером, выдавшим ссылку, чтобы начать скачивать файлы. Это интересная особенность ссылки, которая несколько ломает децентрализованность системы. По-видимому, таким образом достигается некоторая «достоверность» раздаваемых файлов.
Ссылка может быть представлена QR кодом. Это может быть удобно для мобильных устройств. Да, BitTorrent Sync есть для мобилок.
Manual connection
У нас есть ключ или ссылка. Надо их каким-то образом передать тем, кому мы хотим раздать файлы. Они добавят ключ или ссылку в свой BTSync, и раздача начнется. В десктопных клиентах достаточно пройти по ссылке (если она есть). Под Linux придётся воспользоваться пунктом меню для «ручного» добавления ключа или ссылки, он почему-то запрятан довольно далеко, это Options→Manual connection. По умолчанию файлы складываются в подпапку папки ~/BitTorrent Sync. В случае ключа надо еще указать название подпапки.
Ну и всё, раздача пошла.
Pause sync
Мне как-то понадобилось превратить Read Only папку в Read & Write. Штатными средствами для стандартных папок это сделать нельзя. А выкачивать всё заново не хочется. Но помог такой фокус:
  • Ставим папку на Pause, чтобы прекратить синхронизацию.
  • Переносим актуальные файлы (кроме подкаталога .sync и временных файлов .bts) куда-нибудь во временный каталог.
  • Удаляем папку из BitTorrent Sync.
  • Добавляем ту же папку по Read & Write ссылке или ключу.
  • Тут же ставим папку на Pause, чтобы предотвратить скачивание, ведь файлы у нас уже есть.
  • Переносим актуальные файлы из временного каталога обратно в нужную папку BTSync на диске.
  • Распаузиваем синхронизацию папки.
  • BitTorrent Sync производит индексацию папки и обнаруживает в ней файлы, пересчитывает контрольные суммы и выкачивает лишь различия.
  • Профит.
My devices
Кроме раздачи файлов всем желающим, в стиле BitTorrent, BTSync может просто синхронизировать все раздаваемые файлы между различными связанными устройствами (в том числе и мобильными) одного пользователя. Получается что-то вроде Дропбокса, но без облака, а P2P. Не пробовал такой режим, не было необходимости.
BitTorrent Sync таки не свободная программа. Но даже в бесплатном варианте вам предоставляется некоторая инфраструктура. Это трекер, для раздачи файлов в интернетах (в LAN можно без него). Это релей, который используется для передачи данных, если оба клиента сидят за NAT. Это сервер для хостинга ссылок (те самые ссылки на link.getsync.com), сервер обновлений и сервер проверки лицензий.
Есть, конечно, платная версия BitTorrent Sync Pro. За ₽600, в год или разово, можно получить несколько дополнительных плюшек. Продвинутые папочки с более тонкой раздачей прав доступа. Возможность менять права доступа без тех манипуляций, что я описал выше. Более удобную синхронизацию между устройствами. Возможность скачивать не всю папку целиком, а только нужные файлы. Весьма недорого. А возможность выборочного скачивания файлов из папки выглядит весьма полезной в контексте раздачи образов виртуалок.
Syncthing
Конечно же, у проприетарного BitTorrent Sync есть свободный клон. Это Syncthing. Он работает очень похоже. Тоже веб интерфейс. Тоже папочки. Тоже бесплатно предоставляется инфраструктура из трекеров и релеев. Но можно поднять и свои собственные, если хочется.
А вот с правами доступа тут как-то беднее, чем в BTSync. Syncthing больше заточен на синхронизацию папочек между устройствами. И любой узел может вносить изменения в папочку. Единственно, можно объявить одну из копий мастером, чтобы другие стали Read Only.

2016-01-10

О *зации

Только лишь часового пояса маловато. Есть ещё интересные термины. Локализация, она же localization, она же l10n. Кастомизация, она же customization, она же c10n. Интернационализация, она же internationalization, она же i18n. Обожаю эти милые сокращения, где цифра в середине означает количество пропущенных букв.
i18n
Это всё примерно об одном и том же. Чтобы ваше приложение выглядело и работало прилично и понятно для местных жителей и в США, и в Сибири, и в Китае, и в Арабских Эмиратах, и на дне Марианской впадины, и, кто знает, на орбите Плутона.
Это касается, в первую очередь, но не ограничиваясь, языком, на котором ваше приложение общается с пользователем. Язык, это в первую очередь — текст. Но, само собой, это касается и графики, надписи встречаются и на картинках, и звуков, речь ведь может и звучать, в играх, например.
Локализации подлежит целая куча всего. Чтобы сильно не мучаться, определяют некоторую локаль (locale). И для данной локали задают правила, характерные для данной местности. Какие это правила, можно увидеть, например, в man 5 locale.
  • LC_CTYPE — определения того, какие буквы тут большие, какие маленькие, какие цифры и т.п. Слава богу, с появлением Unicode, тут особых проблем и исключений уже нет.
  • LC_COLLATE — правила сортировки, от А до Я или как-то иначе. Тут всё действительно может быть по-разному. Даже европейские языки, использующие латиницу, любят щеголять всякими умлаутами, которые либо входят в алфавит, а, значит, учитываются при сортировке, либо нет.
  • LC_MONETARY — правила форматирования денежных единиц. С одной стороны, тут всё больше зависит от валюты, чем от страны. То же количество знаков после запятой, то бишь размер «цента», у всех валют разный. И свой знак тоже разный (да здравствует знак рубля). Но вот правила размещения знака валюты: до цифры или после, — а также разделители: дробной части числа и тысячей — в каждой стране могут быть разными.
  • LC_NUMERIC — правила форматирования чисел. Ну, в общем, те же деньги, но без знака валюты. Основное дикое различие — десятичная точка или запятая. Особенно убийственно парсить числа. Есть страны, где запятая является разделителем тысяч. Поэтому нарисовать универсальный парсер для всех возможных национальных вариантов написания чисел не представляется возможным.
  • LC_TIME — правила форматирования дат и времени. Подразумевается, что существуют некоторые национальные стандарты представления времени в «кратком» и «длинном» форматах, например. Но лично мне кажется, что формат представления дат больше зависит от самого приложения, чем от местности. Единственное серьёзное исключение — странные северо-американцы, которые единственные в мире почти везде месяц пишут до числа: MM/DD/YYYY, — и могут не сообразить, когда написано по-человечески: DD.MM.YYYY.
  • LC_MESSAGES — это как раз текстовые сообщения.
Правила сортировки, форматы дат и чисел, как правило, уже как-то зашиты в систему или библиотеки, главное, всегда указывать правильную локаль. А вот тексты надо писать и переводить. Тем более, что большинство программ, даже в XXI веке, остаются текстовыми. Поэтому, когда заботятся о локализации, в первую очередь занимаются переводами.
Translate
С давних времён существует милая библиотека gettext. Её использование предполагает, что в исходных текстах программы все строки, которые надо переводить, остаются как есть, лишь обрамляются специальной функцией:
printf(_("Hello, World!\n"));
С помощью специальных инструментов исходники сканируются и составляется полный перечень всех строк для перевода. Идентификатором строки, получается, является оригинальный текст, содержащийся в конкретном месте исходников. Эти строки обрабатываются переводчиком, перегоняются в бинарные файлы, которые уже поставляются вместе с программой. Всё, в общем, продумано и автоматизировано.
В Java оно заметно попроще. Тут не принято писать в исходниках пространные тексты. Тут принято сразу указывать в коде идентификаторы сообщений. И преобразовывать их в конкретный локализованный текст где-нибудь поближе к view. Никаких свободных средств поиска всех айдишников в исходниках или заметного упрощения труда переводчиков мне не известно. Соответствие идентификаторов и текстов записывается в обычные properties файлы. По одному файлу для каждой локали.
Конечно же, локаль — это не только язык. Обычно к языку добавляют еще и страну. Ибо, например, английский в США и английский в Соединённом Королевстве таки заметно различаются. А в китайском есть две системы иероглифов: упрощённая и традиционная. Упрощённая уже давненько применяется в континентальном Китае, а традиционная всё еще жива на Тайване.
В Java к языку и стране можно добавить некий «вариант». Это когда нам надо пойти дальше и выразить более тонкие отличия, т.е. сделать именно то, что называется кастомизацией.
Но офигенно круто к вопросу локализации подошли в Android. Там все ресурсы, а это и сообщения, и изображения, и разметка GUI, и даже размеры чего угодно, разнесены по папочкам. И разные папочки выбираются исходя из громадной кучи параметров: и язык, и страна, и версия Android, и разрешение, размеры и ориентация экрана, и день/ночь, и нахождение устройства в автомобильном доке, и даже код оператора сотовой сети. Действительно очень круто. А ещё все идентификаторы ресурсов «компилируются» в целочисленные константы, и в коде даётся ссылка уже на эти константы, это позволяет на этапе сборки приложения контролировать наличие всех нужных идентификаторов и связанных с ними ресурсов.
Android Resource
Локализованные сообщения как правило наследуются. Если не нашли строчку для конкретного варианта, ищем для данной страны. Если там нет, находим общий перевод на данный язык. Если и там не нашли, откатываемся к локали по умолчанию. Так как нынче у нас самым распространённым языком является английский, в дефолтную локаль имеет смысл засовывать английские тексты. Если у вас действительно международное приложение.
Из-за наследования сообщений возникает феномен частично переведённых приложений. Когда часть текстов в приложении, скажем, по-русски, а местами, что не перевели — по-английски. С одной стороны — неприятно. С другой стороны — заставить переводчиков перевести всё правильно и успеть к релизу — отдельный неблагодарный труд. К тому же сообщения локализации имеют дурную привычку меняться и добавляться. И переводы должны меняться и обновляться соответственно.
А еще есть парочка милых семитских языков: иврит и арабский, — в которых пишут справа налево. Это отдельная проблема для локализации. Ибо там не только тексты справа налево, там весь интерфейс должен быть справа налево, включая все кнопочки, менюшки, чекбоксы, и даже полосы прокрутки. Именно для поддержки этой локализованной право-левости нынче модно выравнивать элементы интерфейса не по левому и правому краю, а по start и end. Start и end могут означать право или лево в зависимости от текущей локали. Хорошо ещё, что верх и низ пока не заменяют более «толерантными» терминами. Видимо, ещё не нашлось письменности, где пишут снизу вверх. Хотя те же китайцы пишут, на самом деле, не слева направо, а сверху вниз.
Отдельная песня — это смешение в одном и том же тексте символов, которые пишутся справа налево, например, букв на иврите, и символов, которые пишутся слева направо, например, арабских цифр. Для этого есть целый большой кусок Юникода под названием bi-directional или BiDi. Смысл в том, что символы (байтики) хранятся в том порядке, в каком они читаются, а при отображении они могут располагаться как справа налево, так и слева направо. Плюс всё это зависит от контекста, т.е. блока, где отображается текст, который тоже может быть слева-направный или справа-налевный. Адовый ад. Есть даже невидимые символы нулевой ширины, которые переключают направление текста.
Но отдельную нелюбовь я питаю к арабскому языку. Он мало того, что справа-налевный, так в нём еще одна и та же буква может отображаться по-разному в зависимости от того, стоит она в начале, середине, или конце слова. Ну вы представляете, эти милые хвостики на конце каждого слова в арабской вязи. Если в вебе это худо бедно работает, то лет восемь назад совсем не было способа программно сгенерировать корректный PDF файл на арабском языке.
Arabic
Как видим, чаще всего локализуют-переводят сообщения целиком. Т.е. целые абзацы текста, ну или как минимум, отдельные предложения. Но часто текст не должен отображаться как есть, к нему нужно что-то добавить, какие-то данные из приложения. Типичный пример: сообщение «Скопировано Х файлов».
Первое, что делают новички, создают два сообщения: «Скопировано» и «файлов», — а потом делают конкатенацию первого сообщения, числа скопированных файлов и второго сообщения. Не надо так. Потому что в каждом языке — свой порядок слов, часто весьма сильно отличающийся. Нужно создать одно сообщение в виде строки форматирования: «Скопировано %d файлов», и подставить в эту строку форматирования нужное числовое значение.
Но тут возникает другая проблема: формы множественного числа. Это в английском всё просто: либо «file», либо «files». А в русском, если кто не в курсе, три формы множественного числа: «1 файл», «2 файла», но «5 файлов». А ведь есть языки, где этих форм ещё больше (опять арабский побеждает, их там шесть).
Стандартная библиотека Java не предоставляет никаких средств для решения проблемы. Я как-то даже писал костылик для русского языка. А вот gettext поддерживает формы множественного числа. В исходниках указываются две строки: для единственного и множественного числа, а вот уже в переводах можно указать все формы данного языка.
Кстати, у строк форматирования есть свои недостатки. Строка форматирования, пришедшая извне (из-за халатности переводчика?) может использоваться как уязвимость в стиле SQL инъекций. Даже название для этого придумали: printf oriented programming. И даже в Java (и в Android) программа может рухнуть при выводе какой-то одной единственной строки только потому, что выполнение наконец дошло до вывода этой строки, а на этом языке переводчик накосячил с символами форматирования, и они не соответствуют передаваемым параметрам.
Но формы множественного числа — это цветочки. В реальности встречаются и другие случаи согласования данных программы и локализованных сообщений. Ну вспомните хотя бы, сколько падежей в русском языке, и представьте, например, как локализовать цвет, хранящийся где-нибудь в БД, чтобы он в виде текста вставлялся во всех возможных формах в локализованные сообщения. Очевидно, что для каждого значения цвета и для каждой локали нужно где-то задать все возможные грамматические формы слова, обозначающего цвет, и выбирать нужную форму исходя из грамматической формы места в строке форматирования.
Возникает соблазн пойти дальше, и вообще дать грамматическое описание всех понятий, встречающихся в приложении. И конструировать предложения из этих понятий. Мне известна только одна библиотека локализации, которая попыталась пойти так далеко. И она носит говорящее название humanization.
Этот подход подкупает душу программиста потрясающей гибкостью. Но это ж надо каждое сообщение описывать почти что на Ыфкуыле. Надо описывать именно понятия, а не слова, ибо существуют синонимы и омонимы, и угадать, как оно будет в других языках, невозможно. Надо разбираться в грамматике всех языков, для которых осуществляется локализация. Видимо, всё же проще переводить фразы и предложения целиком, при этом меньше требования к филологической грамотности разработчиков и переводчиков.
Web Sites Humanization
Думайте о локализации сразу. Потом добавить её будет сложновато. Не хардкодьте.