...

суббота, 22 февраля 2014 г.

Дайджест интересных материалов из мира веб-разработки и IT за последнюю неделю №97 (16 — 22 февраля 2014)

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




Метки лучше разделять запятой. Например: общение, социальные сети, myspace.com, подростки, мердок


или закрыть

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Шифрованный тоннель для общения через VK (RSA + GreaseMonkey)

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

image



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

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



Общая информация




Мотив данного метода — создать канал, управляемый собеседниками без посредника, т.е. не давать возможность серверу видеть незашифрованный текст сообщений. Конечно, типичная man-in-the-middle атака посредством подмены открытого ключа вполне возможна, но очень маловероятна, так как мы опасаемся не прослушки в режиме реального времени, а потенциальной опасности компрометации текста сообщений в ближайшем будущем, например, по запросу спецслужб.

Как я уже говорил выше, была идея создать собственный месенджер (ну вы поняли, с чем). Почему? Из пары причин:


  • Я и мои друзья можем доверять моему продукту;

  • Я могу сделать его таким, как хочу;

  • Это — весело!




Но через некоторые трудности, среди каких — как разработка продукта, так и его внедрение среди непрограммистов. Поэтому в качестве субъекта сих извращений был однозначно выбран ВКонтакте, а платформой для внедрения конечного продукта стал аддон GreaseMonkey:


  • Большинство знакомых пользуется именно ВКонтакте;

  • Довольно просто объяснить процесс разворачивания моего скрипта.


Немного общеизвестных технических данных




Исходя из того, на какую аудиторию рассчитана эта статья, я не буду объяснять процесс установки GreaseMonkey и моего скрипта. Если же вы не знаете, как это сделать — читайте мануал, например, тут (спасибо google за эту ссылку).

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



  • Собеседники обмениваются открытыми ключами. Этот процесс автоматизируется нашим скриптом.

  • Один из собеседников отправляет сообщение. Это сообщение шифруется публичным ключём напарника.

  • Другой из них получает это сообщение. Это сообщение расшифровывается его публичным ключём.


Процесс в картинке:

image


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


Ближе к делу




Итак, что делает скрипт?


  • Внедряет себя в страницу ВК при её открытии, и патчит документ, добавляя ивент на нажатие CTRL+SHIFT+V;

  • По нажатию последней комбинации добавляет кнопки отправки зашифрованных сообщений и генерации публичного ключа для напарника;

  • Реагирует на сообщения вида "%n:открытый_ключ_напарника" и "%m:зашифрованное,сообщение", заменяя их нотификациями про факт получения публичного ключа от напарника либо расшифрованным текстом.

  • Патчит элементы DOM своими атрибутами с префиксом «vksl-» для сохранения своего состояния.


Краткая инструкция




При открытии страницы с чатом в верхнем правом углу должно появится сообщение «VKSL loaded» (возможно, придется нажать F5, если вы перешли с другой страницы). Нажав CTRL+SHIFT+V на странице с чатом, опять таки получим сообщение об успешной (или же неудачной) инъекцией шифратора в код страницы.

После этого каждый из собеседников должен нажать на линк «GENERATE KEYS NOW». Через несколько (возможно, десятков) секунд появится сообщение, что ключ сгенерирован и отправлен. Следовательно, собеседние на другом конце будет тоже уведомлен об этом.

Теперь можно приступать к общению. Для отправки обычного сообщения пользуемся стандартной кнопкой, для отправки шифрованного — нажимаем на «SEND ENCRYPTED». Скрипт на другом конце сам поймёт, что нужно делать, если получено зашифрованное сообщение.

Проблеммы, которые до сих пор было лень устранить (а следовало бы)





  • Скрипт не работает в конференциях, а рассчитан лишь на двустороннее общение.

  • Максимальная длина сообщения на данный момент лишь 32 байта — нужно шифровать, разбивая текст на блоки, а не так, как там сейчас.

  • По нажатию на «Enter» вызывается нативная отправка. Нужно немного больше порыться в коде, чтобы заменить и этот ивент.

  • Аттачменты не шифруются, поскольку они фактически не являются частью сообщения.


Установить скрипт можна отсюда: http://ift.tt/1jW3End

Желающие потестить: можете писать мне сюда.

Спасибо за ваше внимание!


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Дыра в безопасности iPhone, или как я навсегда отказался от продукции Apple

Начало




Начнем с преамбулы.

Телефоном/смартфоном я пользуюсь исключительно как средством связи — вызовы, смс, почта, соц.сети.

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

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

В общем, недавно я стал «счастливым» обладателем iPhone 5s, счастье правда длилось недолго.

Скажу сразу, все последующее относится к последней версии iOS7, с последним обновлением 7.0.6, c исправленной дырой при ssl.



Информация



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

Не помню, предлагал ли мне айфон из коробки поставить этот самый пароль. Вроде бы нет.

Моя позиция проста — если я потеряю телефон, или у меня его украдут — я просто поменяю все свои пароли, а данных непосредственно на устройстве у меня нет.
Суть.



А суть проблемы в сафари. Точнее, в сохраненных сафари паролях.

Если вы пройдете по пути Настройки->Safari->Пароли и автозаполнение->Сохраненные пароли, то там будет список сайтов/аккаунтов, которые вы когда-либо сохраняли в сафари.

Вот только эти пароли там хранятся в открытом виде.

Да, в открытом.

Т.е. СИМВОЛЬНО.

Т.е. любой человек, взявший на пару минут мой телефон, может посмотреть МОЙ ПАРОЛЬ, В ОТКРЫТОМ ВИДЕ.

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

Но из-за этой фичи iOS7 он может узнать пароль. И дальше делать это уже не единожды.

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

Мой вопрос, который я задаю здесь в открытом виде — почему я не был нигде предупрежден, что пароли хранятся в открытом виде?

Особенно, когда сафари предлагал мне сохранить их.

Служба поддержки молчит.

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


И да, там же есть и вся информация о хоть раз введенных на каком-либо сайте данных кредитных карт, кроме CVC.


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


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


[Из песочницы] Vсем Pо Sерверу или масштабное тестирование VPS

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

Для тестирования были рандомным способом отобраны 7 отечественных хостинг-провайдеров, предоставляющие услуги тестового периода для VPS (VDS), чем я не мог не воспользоваться в своих благих целях. Стоимость VPS варьируется от 500 до 700 рублей и относятся к бюджетному сегменту. Итак, наши претенденты:


image



Методология тестирования:




Метод тестирования прост — с удаленного сервера отправляем тонны запросов на WEB сервер и смотрим, как ведет себя VPS. Можно сказать, что это небольшой DDos.

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

  • Intel i7 2600 Quad-Core + Hyper-Threading;

  • 32 Гб ОЗУ;

  • 1 Гбит канал.




На всех тестируемых VPS установлена ОС – Debian 7 x64. В тех случаях, где хостер не поддерживает данную ОС используется другая ОС, о чем указано выше в описании претендентов.

Основное установленное ПО на VPS (Debian 7):

  • Apache 2.2.22;

  • PHP 5.4;

  • MySQL 5.5.




Основное установленное ПО на VPS (Debian6):

  • Apache 2.2.16;

  • PHP 5.3;

  • MySQL 5.1.




Чтобы получить максимально точные результаты всем VPS были созданы идентичные условия: все ПО я устанавливал самостоятельно. WEB сервера работают на голом Апаче (NGINX и прочие приятности не устанавливались), все конфиги по дефолту. На все VPS была установлена Joomla 3.1.5 с демо данными блога. В качестве ПО для самого теста использовался Apache Benchmark версии 2.3.

Для каждого VPS тестирование проводилось в 3 этапа:



  1. Первый этап – 30 потоков и 500 запросов.

  2. Второй этап – 50 потоков и 1 000 запросов.

  3. Третий этап – 100 потоков и 10 000 запросов.




Количество потоков можно приравнять к посетителям сайта, а количество запросов к запросам от этих посетителей к WEB серверу VPS.

Например, первый этап можно представить, как 30 пользователей на сайте одновременно и в общей сложности сделали 500 запросов WEB серверу.

Каждый этап прогонялся 3 раза и в качестве результирующих использовались средние значения из результатов теста.

В таблице учитывались основные, на мой взгляд, параметры:



  • Неудачные запросы (Failed requests) – количество запросов, которые VPS не смог обработать.

  • Количество запросов в секунду (Requests per second) – тут все ясно из названия, чем больше запросов в секунду обрабатывает WEB сервер, тем выше его скорость работы.

  • Время выполнения 1 запроса (...across all concurrent requests) – чем меньше данное значение, тем быстрее WEB сервер обрабатывает запросы и тем выше общая скорость работы.

  • Время выполнения всех запросов (Time per request) – общее время на обработку всех отправленных на WEB сервер запросов. Чем меньше значение, тем лучше.

  • Время соединения (Connection Times) – состоит из

    a. Строка Connect: — время, которое потратила утилита на соединение с сервером.

    b. Строка Processing: — время выполнения запроса.

    c. Строка Waiting: — время простоя запроса. То есть время, которое запрос ждал своей очереди для выполнения.

    d. Строка Total — Общее время.


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



  • Общее время на тест (Time taken for tests) – зачастую совпадает с общим временем обработки всех запросов. Чем меньше значение, тем лучше.


В тесте не дается оценка таким характеристикам, как дисковая подсистема, объем внешнего канала, стоимость и качество доп.услуг.


Тестирование:




Первый раунд: 30 поток и 500 запросов.

И в первом же тесте VPS от 1gb.ru не смог обработать даже 100 запросов. С чем это связано сказать сложно, у меня не было цели разбираться о причинах столь фатального выступления данного претендента, поэтому идем дальше.

Следующий претендент от Timeweb показал себя намного лучше и без особых усилий справился с задачей, обработав все отправленные на его WEB сервер запросы:



















Неудачные запросыКол-во запросов в сек.Время выполнения 1 запросаВремя выполнения всех запросовВремя соединенияОбщее время
06.2161.3 мс.4758 мс.1616 — 8988 мс.79.6 сек.



Далее «атаке» подвергся VPS от Agava, который также успешно справился со своей задачей:


















Неудачные запросыКол-во запросов в сек.Время выполнения 1 запросаВремя выполнения всех запросовВремя соединенияОбщее время
010.199.1 мс.2981 мс.827 — 5373 мс.49.5 сек.



Следующий претендент – infobox:


















Неудачные запросыКол-во запросов в сек.Время выполнения 1 запросаВремя выполнения всех запросовВремя соединенияОбщее время
03.4291.7 мс.8750 мс.1524 — 10142 мс.145.8 сек.



Следом в деле себя показал хостинг от It-mcp:


















Неудачные запросыКол-во запросов в сек.Время выполнения 1 запросаВремя выполнения всех запросовВремя соединенияОбщее время
02.3436.4 мс.13091 мс.2662 — 15462 мс.218 сек.



Предпоследний кандидат – Fozzy:


















Неудачные запросыКол-во запросов в сек.Время выполнения 1 запросаВремя выполнения всех запросовВремя соединенияОбщее время
05.3189.5 мс.5685 мс.1304 — 7210 мс.94.7сек.



И завершает первый этап тестирования VDS24.net:


















Неудачные запросыКол-во запросов в сек.Время выполнения 1 запросаВремя выполнения всех запросовВремя соединенияОбщее время
010.496.5 мс.2895 мс.919 — 4941 мс.48.3 сек.



Подведем первый промежуточный итог:

Все VPS, кроме 1gb, справились с заданием, поэтому 1gb выбывает из дальнейших тестов. Лидером по скорости, после первого этапа, является VDS24, на втором месте VPS от Agava. Переходим к раунду 2.

Второй раунд: 50 потоков и 1000 запросов.


Timeweb:



















Неудачные запросыКол-во запросов в сек.Время выполнения 1 запросаВремя выполнения всех запросовВремя соединенияОбщее время
4494.6218.4 мс.10919.5 мс.538 — 38114 мс.218.4 сек.



Во втором раунде Timeweb не смог справиться с задачей и смог обработать только чуть больше половины запросов.

image

Agava:


















Неудачные запросыКол-во запросов в сек.Время выполнения 1 запросаВремя выполнения всех запросовВремя соединенияОбщее время
07.6131.5 мс.6574.7 мс.635 — 9781 мс.131.5 сек.



Infobox:


















Неудачные запросыКол-во запросов в сек.Время выполнения 1 запросаВремя выполнения всех запросовВремя соединенияОбщее время
03.4291.3 мс.14563.8 мс.2018 — 16325 мс.291.3 сек.



It-mcp:


















Неудачные запросыКол-во запросов в сек.Время выполнения 1 запросаВремя выполнения всех запросовВремя соединенияОбщее время
02.3436.6 мс.21827.7 мс.2548 — 24240 мс.436.6 сек.



Fozzy:


















Неудачные запросыКол-во запросов в сек.Время выполнения 1 запросаВремя выполнения всех запросовВремя соединенияОбщее время
05.5182.7 мс.9133.7 мс.1620 — 11103 мс.182.7 сек.



VDS24:


















Неудачные запросыКол-во запросов в сек.Время выполнения 1 запросаВремя выполнения всех запросовВремя соединенияОбщее время
09.6104 мс.5202.3 мс.987 — 10296 мс.104 сек.



По результатам второго этапа тестирования по-прежнему с небольшим отрывом лидирует VDS24, ему в спину дышит Agava. В хвосте списка плетется It-mcp.

Третий раунд: 100 потоков и 10000 запросов.

Timeweb:

В третьем раунде у Timeweb при всех 3 попытках намертво падал MySQL и Apache выдавал невеселое сообщение: Error displaying the error page: Application Instantiation Error. Тестируемый сайт оживал только после рестрата MySQL. На третьем этапе VPS от Timeweb пополняет ряды отстающих, вкупе с 1gb.

Agava:



















Неудачные запросыКол-во запросов в сек.Время выполнения 1 запросаВремя выполнения всех запросовВремя соединенияОбщее время
07.6125.8 мс.12576 мс.606 — 15627 мс.1257.6 сек.



Infobox:


















Неудачные запросыКол-во запросов в сек.Время выполнения 1 запросаВремя выполнения всех запросовВремя соединенияОбщее время
03.4292.2 мс.29216.5 мс.1576 — 35362 мс.2921.6 сек.



It-mcp:


















Неудачные запросыКол-во запросов в сек.Время выполнения 1 запросаВремя выполнения всех запросовВремя соединенияОбщее время
02.34396.1 мс.43961.3 мс.2683 — 81978 мс.4396.1 сек.



Fozzy:


















Неудачные запросыКол-во запросов в сек.Время выполнения 1 запросаВремя выполнения всех запросовВремя соединенияОбщее время
05.21910.3 мс.19103.4 мс.1488 — 23609 мс.1910.3 сек.



VDS24:

Мы подошли к нашему лидеру первых двух этапов. И тут нас постигает разочарование. VDS24 при всех трех попытках намертво зависал, сумев обработать лишь чуть более 2000 запросов.

На этом третий этап тестирования завершен.


Итоги:




Победителем нашего тестирования, продемонстрировавшим весьма неплохую скорость работы и отказоустойчивость, объявлен VPS от Agava.

Аутсайдером нашего теста, конечно же, стал VPS от 1gb, который смог справиться лишь с 10 потоками и 50 запросами.

Итоговая таблица выглядит так:

  1. Agava

  2. Несмотря на провал в последнем тесте, второе место я отдаю VDS24

  3. Fozzy

  4. Infobox

  5. It-mcp

  6. Timeweb

  7. 1gb




Для эксперимента была сделана попытка проверить возможности еще не выпавших из гонки VPS. Им в нагрузку было отправлено 300 потоков и 50 000 запросов. Скажу сразу, что никто с такой нагрузкой так и не справился.

Конечно мы смогли протестировать далеко не все VPS, которые есть на рынке, также скорость работы и отказоустойчивость можно значительно повысить грамотной настройкой VPS, но потенциал был хорошо прослежен в данном тесте. Как выяснилось далеко не всегда производительность упирается в мегагерцы и объемы ОЗУ.


Ознакомиться со сводной таблицей результатов тестирования можно здесь.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Адам Лэнгли объяснил причины бага в iOS: лишняя строчка кода поломала всю безопасность

Вчера компания Apple выпустила обновление безопасности iOS 7.0.6 для iPhone 4 и более поздних моделей, iPod touch 5-го поколения и iPad 2+. Одновременно выпущен аналогичный патч 6.1.6 для iPhone 3GS и iPod touch 4-го поколения.

Обновление закрывает уязвимость CVE-2014-1266, которая позволяет злоумышленнику из «привилегированной позиции в сети» перехватывать и модифицировать пакеты в сессиях, защищённых SSL/TLS. Речь идёт о MiTM-атаке с подменой трафика.


В лаконичном пояснении Apple говорит, что при установке защищённого соединения по SSL/TLS система не способна определить аутентичность соединения. Проблему решили путём «добавления недостающих этапов валидации».



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


Сегодня известный криптограф Адам Лэнгли опубликовал статью с анализом бага в iOS. Он обращает внимание на разницу в коде OS X 10.8.5 (Security-55179.13) и 10.9 (Security-55471), где, вероятно, исправлен тот же самый баг.


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



static OSStatus
SSLVerifySignedServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer signedParams,
uint8_t *signature, UInt16 signatureLen)
{
OSStatus err;
...

if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
...




облом:

SSLFreeBuffer(&signedHashes);
SSLFreeBuffer(&hashCtx);
return err;
}




Процитировано с опубликованных исходников Apple.

Обратите внимание на две строки goto fail подряд. Первая из них корректно связывается с оператором if, а вторая вообще не имеет никакого отношения к делу. В результате, выполнение программы всегда завершается на этом этапе, со второго goto fail. Значение err содержит правильное значение, потому что операция обновления SHA1 была успешной и верификация подписи всегда даёт «добро».


Речь идёт о проверке подписи в сообщении ServerKeyExchange, что используется в шифрах DHE и ECDHE для передачи одноразового ключа соединения. Сервер говорит: «Вот одноразовый ключ, а вот подпись от моего сертификата, так что ты знаешь, что ключ от меня». В случае с Apple, если связь между одноразовым ключом и сертификатом сломана, то вся система разваливается. Теперь вообще ничего не работает: можно отправить клиенту правильный сертификат, но подписать рукопожатие произвольным секретным ключом, или вообще его не подписывать! Отсутствуют любые доказательства, что сервер, который присылает сертификат, вообще владеет секретным ключом для этого сертификата.


Уязвимость, вероятно, присутствует во всех версиях iOS до 7.0.5 и во всех версиях OS X до 10.9.1 включительно.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Словари: мифы и реальность. Лекция в Яндексе

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



Читает лекцию кандидат филологических наук Борис Леонидович Иомдин, старший научный сотрудник Института русского языка им. В. В. Виноградова РАН, доцент Института лингвистики РГГУ, доцент факультета филологии Высшей школы экономики.



Как возникли и развивались словари




Первые подобия словарей появились в XXV веке до н.э. у шумеров. Это были так называемые глоссы: на полях рукописей выписывались значения незнакомых слов. Ну а первый известный нам полноценный словарь, представляющий собой отдельную книгу, появился в Китае в XX веке до н.э. Называется он Erya (爾雅 [Ěryǎ]) и состоит из 2094 словарных статей. Всего в нем растолковываются 13 113 иероглифов, написанных на 19 пянях – связках из 20-30 бамбуковых планок, размером 1 см на 20-40 см. Современные наиболее полные словари китайского языка содержат толкования около 60 000 иероглифов, а образованные носители китайского языка за свою жизнь выучивают в среднем около 10 000 иероглифов. Так что, несмотря на древность, словарь Erya можно назвать достаточно полным. Так как в китайском языке нет алфавита, словарные статьи в нем упорядочены по тематике: термины родства, жилища, утварь, музыкальные инструменты, небесные тела, территории, возвышенности, горы, воды, травы, деревья, насекомые, рыбы, птицы, дикие животные, домашние животные.

Примерно в 100 году н.э. появился Shuōwén Jiězì – первый словарь, где иероглифы были разбиты по ключам: группировка производится по базовым графическим элементам иероглифов, что упрощает поиск толкований иероглифов в тех случаях, когда даже примерное значение слова неизвестно. Словарь содержит 9353 иероглифов, известен его автор: Сюй Шень.


image


Самый ранний из дошедших до нас рукописных славянских словарей – это так называемый азбуковник. Он был создан в 1282 в качестве приложения к Кормчей книге и содержа толкования 174 слов. Ну а самый первый печатный словарь был издан в 1596 году в качестве приложения к грамматике Лаврентия Зизания.


image


В нем содержится перевод 1061 слова со старославянского языка на древнерусский.


Расцвет лексикографии




На протяжении большей части истории своего существования, словари были литературой исключительно для профессионалов, и среди простых людей не пользовались особой популярностью, да и не были особенно доступны. Тот бум словарей, который наблюдается сейчас, стал проявляться только в середине двадцатого века, когда стало понятно, что словарь не просто книга, в которой разъясняются непонятные слова, а в некотором роде проводник культуры. Один из опросов, проводившихся в 90-е годы в Великобритании, показал, что хотя бы один толковый словарь есть в 90% британских семей. Больше, чем поваренные книги (70%) и Библия (80%).

Возникли целые семейства словарей, составляемые едиными коллективами авторов по единым принципам:



  • Random House Webster, Barnhart, American Heritage (США);

  • Oxford, Chambers, Collins, Hamlyn, Longman, Macmillan (Великобритания);

  • Le Robert, Larousse, Tresor (Франция);

  • Duden (Германия);

  • Словари Академии наук (СССР, Россия).


Следи толковых словарей русского языка можно выделить:


  • БАС – Словарь современного русского литературного языка в семнадцати томах.

  • М.–Л.: Изд-во АН СССР, 1950–1965.

  • МАС – Словарь русского языка в четырех томах. / Под ред. А. П. Евгеньевой. М.: Русский язык, 1981–1984.

  • СОШ – Ожегов С.И., Шведова Н.Ю. Толковый словарь русского языка. Изд. 4-е. М.: Русский язык, 1997.

  • БТС – Большой толковый словарь русского языка / Сост. С. А. Кузнецов. СПб., 1998.

  • СШ – Толковый словарь русского языка с включением сведений о происхождении слов / Отв. ред. Н. Ю. Шведова. М., 2007.

  • НБАС – Большой академический словарь русского языка. Гл. ред. А. С. Герд. СПб., 2012. На данный момент издан 21 том, начинающийся со слова «проделать» и заканчивающийся словом «пятью».




Как составляются словари




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

До тех пор, пока компьютеры не обрели широкого применения, определения записывались на карточки, из них составлялись картотеки. Труднее всего было находить примеры применения слов в художественной литературе. Академик А. А. Зализняк высказывался об этом следующим образом: «Нынешним молодым людям уже трудно представить себе, что эта работа делалась вручную. «Это же немыслимый абсурд – делать такую работу без компьютера», – доводилось мне слышать. В действительности рабочим инструментом были четыре хлебных лотка, раздобытых в соседней булочной; в каждый входило по 25 тысяч карточек из тонкой бумаги».


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


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


Чего не хватает словарям




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


  • I, YOU, SOMEONE, PEOPLE, SOMETHING, BODY

  • KIND, PART; THIS, THE SAME, OTHER

  • ONE, TWO, SOME, ALL, MANY, FEW

  • GOOD, BAD; BIG, SMALL

  • THINK, KNOW, WANT, FEEL, SEE, HEAR

  • SAY, WORDS, TRUE

  • DO, HAPPEN, MOVE, TOUCH

  • BE, THERE IS, HAVE; LIVE, DIE

  • WHEN, NOW, BEFORE, AFTER, A LONG TIME, A SHORT TIME, FOR SOME TIME, MOMENT

  • WHERE, HERE, ABOVE, BELOW, FAR, NEAR, SIDE, INSIDE

  • NOT, MAYBE, CAN, BECAUSE, IF

  • VERY, MORE; AS




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


  • (a) X felt something because X thought something

  • (b) sometimes a person thinks:

  • (с) «I know now: something very good will happen

  • (d) I want it to happen

  • (e) I can't think about other things now»

  • (f) when this person thinks this this person feels something good

  • (g) X felt something like this

  • (h) because X thought something like this




Или на примере слова ashamed:


  • (a) X felt something because X thought something

  • (b) sometimes a person thinks:

  • (с) «people can know something bad about me

  • (d) I don't want people to know this

  • (e) if people know this they can't not think smt bad about me

  • (f) when I think about it, I can't not think the same»

  • (g) when this person thinks this this person feels smth bad

  • (h) X felt something like this

  • (i) because X thought something like this




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

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


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Сниппет ddTypograph 2.0b на EMT lib 3.2 (MODX Evo)

Здравствуйте!

Не так давно Евгений Муравьёв выпустил совсем новую версию своего знаменитого типографа 3.0. Любому продукту надо чуть-чуть обкататься, самые первые версии как правило сыроватые, потому подождали версии 3.2 и начали его смотреть. Надо сказать, что в целом новый типограф оставил положительные впечатления.


image



Он стал удобнее, линейная передача параметров в текущей версии гораздо проще для понимания. Теперь, если нам нужна автоматическая расстановка параграфов, просто выставляем опции ‘Text.paragraphs’ значение ‘on’ (или ‘off’, чтобы отключить). Не понятно, правда, почему не использовались привычные булевые true и false, но да ладно, это не так важно.


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


Интересной особенностью новой версии библиотеки является размещение всего кода в одном файле (3 281 строка). С одной стороны, это не очень удобно для понимания кода (да и рефакторить, наверное, не удобно), с другой, проще для конечных пользователей — один файлик гораздо менее страшен, вызывает меньше отторждения, чем 13 =)


Слегка огорчило отсутствие нормальной документации, пришлось чуть-чуть поковыряться в коде, но довольно быстро был найден метод «get_options_list», который выводит список всех опций с человеческим описанием (но, к сожалению, не для всех опций описаний достаточно). Ещё сильно не хватает библиотеки на GitHub.


В конце-концов, мы выпустили новую версию сниппета ddTypograph 2.0b. Опций у библиотеки достаточно много, но в сниппете мы посчитали целесообразным сделать лишь 4:



  1. «OptAlign» — оптическое выравнивание (висячая пунктуация).

  2. «Text_paragraphs» — простановка параграфов и переносов строк.

  3. «Text_autoLinks» — выделение ссылок из текста (в том числе email).

  4. «Etc_unicodeConvert» — преобразовывать html-сущности в юникод (— вместо — и т.д.).




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

Помогите пожалуйста потестировать сниппет. Может быть что-то работает не очень хорошо или не хватает каких-то жизненно-важных опций для ваших задач. Мы будем рады услышать ваши мысли здесь в комментариях или же по email (code@divandesign.biz).


P.S.: Изображение в посте использовано с сайта mdash.ru, надеюсь, авторы общественного достояния не против ;-).


P.P.S.: emuravjev, если вы это читаете, ответьте пожалуйста на моё письмо или в скайпе.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


[Из песочницы] Производительность RAID массивов

Уверен, что каждый системный администратор сталкивался с вопросом какой raid массив использовать для той или иной задачи. Хочу поделиться своими мыслями, цифрами и рассуждениями на эту тему.

Задача — планирование места для размещение виртуальных машин на системе хранения данных.


Используемое аппаратное и программное обеспечение для тестирования — VMWare ESXi 5.5 на HP ProLiant DL380 Gen8, виртуальная машина Windows 2008 R2 Enterprise (2 CPU, 4 Gb RAM, 60 Gb HDD), дисковая система HP P2000 G3 MSA FC, диски HP SAS 600Gb 10k, программа оценки скорости Cristal Disk Mark.


Цель — подбор типа raid массива.



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


Выводы — всегда понятнее манипулировать цифрами. В интернетах много картинок что «быстрее», «отказоустойчивее» и т.д. Отказоустойчивость более понятный параметр — 1 или 2 диска, время восстановления после замены диска требует отдельного исследования. Картинки «попугаев» и прочих животных по конкретным дискам так же не очень подходят под нашу задачу, по скольку многое зависит от raid-контроллера.


В этой статье рассматриваем параметр «быстрее». Понимаю, что все зависит от конкретного железа, по этому указываю точную конфигурацию.


Результат — после проведения замеров для себя определили использование массивов Raid50 и Raid10.


Чтобы не быть голословным прикрепляю картинки замеров.













Raid0 на 4 дисках:



Raid0 на 12 дисках:



Raid10 на 4 дисках:



Raid5 на 9 дисках:



Raid50 на 8 дисках:



Raid6 на 4 дисках:



Все на одном.


Слева на право: raid50, raid6 (2 измерения в разное время), raid5, raid10. Внизу справа: raid0 4 disk, raid 0 12 disk:



This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Увеличение бюджетных мест по ИТ-специальностям в ВУЗах РФ в 2015-2016 учебном году


сегодня в 15:54


Министерство образования и науки утвердило контрольные цифры приема (КЦП) на 2015–2016 учебный год по ИТ-специальностям. По итогам совместной работы профильных ведомств КЦП по ИТ-специальностям в целом увеличились на 34%. При этом прием по программе магистратуры на специальности «информатика и вычислительная техника» увеличился на 74%, «информационные системы и технологии» — на 208%, «прикладная информатика» — на 191%, «инфокоммуникационные технологии и системы связи» — на 202%. [К сожалению, мне не удалось найти оригинал постановления на сайте Минобрнауки.]



В июле 2013 г. министр связи Николай Никифоров, представляя на заседании Правительства подготовленную Минкомсвязи «Стратегию развития отрасли ИТ в РФ на 2014–2020 гг. и на перспективу до 2025 г.» [о чём была статья на Хабре], отдельно выделил направление подготовки кадров в качестве одного из главных. Министр констатировал серьезный дефицит специалистов. Сейчас в отрасли занято около 300 тыс. человек., еще 700 тыс. ИТ-специалистов работают в ней косвенно (сотрудники ИТ-департаментов компаний-заказчиков ИТ). «Потребность до 2018 г. оценивается более чем в 350 тыс. человек, — оценивает Никифоров. — Из них 150 тыс., как мы понимаем, будут подготовлены в рамках бюджетной основы по линии Минобрнауки, таким образом, остается дефицит в объеме около 200 тыс. человек».

Иточник: Сайт Минкомсвязи РФ





Свежий взгляд

на бег


протестируй кроссовки

нового поколения




Стань

первоиспытателем!


Скачай Windows Server 2012 R2

и выиграй почетную футболку!


Скачать




Автоматизированное

продвижение сайтов




  • 50% экономии на ссылках

  • Запуск проекта за 10 минут

  • Вывод и удержание в ТОП 10



Подробнее




Новый 3G-планшет Login 2



2790 р.*


*Условия акции на www.megafon.ru

Подробнее



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


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


[Из песочницы] Мощный лабораторный блок питания

Не так давно приобрёл паяльную станцию. Давно занимаюсь любительской электроникой, и вот настал момент когда точно осознал что пора. До этого пользовался батиным самопальным блоком, совмещавшим лабораторный блок питания и блок питания низковольтного паяльника. И вот встала передо мной проблема: паяльную станцию я ставлю, а старый блок держать ради хилого и не точного блока питания 0-30в 3А или таки купить нечто современное, с защитой по току и цифровыми индикаторами? Поползав по ебею понял что максимум что мне светит это за 7-10 тыс купить Китайский блок с током максимум в 5А. Жаба сказала своё веское «ква», руки зачесались и…



Теперь к сути. Сформировал требования к блоку: минимум 0-30В, при токах минимум 10А, с регулируемой защитой по току, и с точностью регулировки по напряжению 0.1В. И что б стало ещё интереснее — 2 канала, пусть и от общей земли. Установка напряжения должна быть цифровой, т.е. никаких переменных резисторов, только энкодеры. Фиксированные установки напряжения и запоминание — опционально.

Для индикации состояния выхода были выбраны цифровые китайские комбинированные индикаторы на ЖК, с диапазоном до 199В с точностью 0.1В и до 20А с точностью 0.01А. Что меня полностью устроило. А вот что забыл, так это прикупить к ним шунты, т.к. по наивности думал что они будут в комплекте.


Для первичного преобразования напряжения думал использовать обычный трансформатор с отводами через каждые 6В, коммутируемый релюшками с контроллера, а для регулировки выхода простой эмиттерный повторитель. И всё бы ничего, но когда узнал стоимость и габариты такого трансформатора (30В * 10А = 300вт), то понял что надо быть современнее и использовать импульсные блоки питания.


Пробежавшись по предложениям понял что ничего толкового на мои токи нет, а если и есть, то жаба категорически против. В связи с этим пришла мысль попробовать использовать компьютерные блоки питания, коих всегда у любого ITшника предостаточно. Были откопаны блоки по 350Вт, что обещало 22А по +5В ветке и 16А по 12В. Пробежавшись по интернету нашёл много противоречивых мнений по поводу последовательного соединения блоков, и нашёл умную статью на Радиокоте как это сделать правильно. Но перед этим решил рискнуть и таки взять и нахрапом соединить блоки последовательно, дав нагрузку.


… И получилось!

На фото последовательно соединены 3 блока. Де-факто на выходе 35В, 10.6А.


image


Далее возник вопрос: каким контроллером управлять. По идее ATMega328 тут идёт за глаза, но ЦАПы… Посчитав почём обойдётся хотя б 2 ЦАПа на 12 бит и посмотрев характеристики Arduino DUE с ними на борту, а так же сравнив кол-во требуемых ПИНов, понял что проще и дешевле и быстрее будет просто поставить эту ардуину в блок целиком, вместе с платой.


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


image


Схема бьётся на несколько функциональных блоков: Набор блоков питания ATX, блок коммутации БП, блок усилителя напряжения ЦАП Arduino, блок усилителя напряжения токового шунта, блок ограничения напряжения по заданному току.


Блок коммутации БП: В зависимости от заданного пользователем напряжения Ардуино выбирает какую ветку задействовать. Выбирается минимальная по напряжению ветка, на минимум +3В большая заданного. 3В остаются на неточности установки напряжения в блоках питания + ~1.2В просада напряжения на переходах транзистора + не большой запас. Одновременно задействованный ключ ветки активирует тот или иной блок питания. Например задав 24В надо активировать все 3 блока питания и подключить выход на +5в 3-го в цепочке, что даст на коллекторе выходного транзистора VT1 +29В, тем самым минимизируя выделяемую тепловую мощность транзистора.


Блок усилителя напряжения: Реализован на операционном усилителе OP1. ОУ используется Rail-to-Rail, однополярый, с большим напряжением питания, в моём случае — AD823. Причём выход ЦАП Ардуино имеет смещение нулевой точки = 0.54В. Т.е. если Вы задаёте напряжение выхода = 0, на выходе де-факто будет присутствовать 0.54В. Но нас это не устраивает, т.к. ОУ усиливает с 0, и напряжение тоже хочется регулировать с 0. Поэтому применён подстроечный резистор R1, вычитающий напряжение. А отдельный стабилизатор на -5В, вместо использования -5В ветки блока питания, используется ввиду нестабильности выдаваемого блоком питания напряжения, меняющимся под нагрузкой. Выход же ОУ охвачен обратной связью с выхода VT1, это сделано что б ОУ сам компенсировал изменения напряжения в зависимости от нагрузки на выходе.


Кстати, о AD823 из Китая по Ебею: день промучился, понять не мог, почему схема не работает от 0 на входе. Если больше 1.5В то всё становится нормально, а иначе всё напряжение питания. Уже подумав что сам дурак, нарвался на рассказ как человек вместо AD823 получил с Китая подделку. Тут же поехал в соседний магазин, купил там, поставил и… О чудо — всё сразу заработало как надо. Игра, найди отличия (подделка в кроватке, справа оригинал. Забавно что подделка выглядит лучше):


image


Далее усилитель напряжение токового шунта. Поскольку токовый шунт достаточно мощный, то и падение напряжения на нём мало, особенно на малых токах. Поэтому добавлен OP2, служащий для усиления напряжения падения шунта. Причём от быстродействия этого ОУ зависит скорость срабатывания предохранителя.


Сам предохранитель, а точнее блок ограничения тока, реализован на компараторе OP2. Усиленное напряжение, соответствующее протекаемому току, сравнивается с напряжением, установленным электронным потенциометром и если оно выше — компаратором открывается VT2, и тот сбрасывает напряжение на базе выходного транзистора, по сути выключая выход. В работе это выглядит так:


image


Теперь к тому, почему в качестве шунта у меня дроссель. Всё просто: как я писал раньше — я просто забыл заказать шунты. А когда уже собирал блок и это выявилось, то ждать с Китая показалось долго, а в магазине дорого. Поэтому не долго думая, порылся в распайке старых компьютерных блоков питания и нашёл дроссели, почти точно подошедшие по сопротивлению. Чуть подобрал и поставил. Дополнительно же это даёт защиту: В случае резкого изменения нагрузки, дроссель сглаживает ток на время, достаточное что б успел отработать ограничитель тока. Это даёт отличную защиту от КЗ, но есть и минус — импульсные нагрузки «сводят блок с ума». Впрочем, для меня это оказалось не критично.


В итоге у меня получился вот такой блок питания:

image

Надписи на лицевой части сделаны с помощью ЛУТа. Индикаторы работы блоков питания выведены на 2-х цветный светодиод. Где красный запитан от дежурных +5в и показывают что блок готов к работе. А зелёный от Power_Good, и показывает что блок задействован и исправен. В свою очередь транзисторная развязка обеспечивает гашение красного светодиода и если у блока проблема — потухнет и красный и зелёный:


image


Маленькие экраны показывают заданные параметры, большие — состояние выхода де-факто. Энкодерами вращением устанавливается напряжение, короткое нажатие — вкл/выкл нагрузки, длинное — выбор режима установки напряжения/максимального тока. Ток ограничен 12.5А на канал. Реально в сумме 15 снимается. Впрочем — на той же элементной базе, с заменой блоков питания на нечто 500-т Ваттное, можно снимать и по 20. Не знаю, стоит ли приводить тут код скетча, простыня большая и достаточно глупая, + везде торчат хвосты под недоделанный функционал вроде коррекции выходного напряжения по АЦП обратной связи и регулировки скорости вентилятора.


Напоследок, пара слов. Оказалось что Arduino DUE при включении после длительного простоя может не начать выполнять программу. Т.е. включаем плату, думаем что сейчас начнёт выполняться наша программа, а в ответ тишина, пока не нажмёшь reset. И всё бы ничего, но внутри корпуса reset нажимать несколько затруднительно.

Поискал по форуму, несколько человек столкнулось с такой же проблемой, но решения не нашли. Ждут когда разработчики поправят проблему. Мне ждать было лениво, поэтому пришлось решать проблему самому. А решение нашлось до безобразия примитивное, впаять электролитический конденсатор на 22мкФ в параллель кнопке. В результате, на момент запуска, пока идёт заряд этого конденсатора, имитируется нажатие кнопки reset. Отлично работает, прошиваться не мешает:


image


В заключение:

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


Ещё хотелось бы через АЦП обратную связь с блоком коммутации на случай залипания релюшки, а так же обратную связь по выходу, дабы компенсировать температурный дрейф подстроечных резисторов (в пределах 0.1в на больших напряжениях бывают отклонения).


А вот кнопки памяти и фиксированные настройки по опыту использования кажутся чем-то не нужным.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Neovim: современный клон текстового редактора Vim

Vim — мощный текстовый редактор, у которого большая аудитория. Хотя программе более 20 лет, её функциональность продолжают улучшать через скрипты vimscript. Последняя версия свободного редактора Vim 7.4 вышла в августе 2013 года.

Проблема в том, что за два десятилетия Vim разросся до страшных размеров: около 300 000 строк кода на C89. «Очень мало людей могут понять этот код или имеют смелость изменять его. Есть проблема и с добавлением нового кода и патчей в Vim: единственный мейнтейнер не успевает за развитием экосистемы плагинов», — пишет бразильский программист Тиаго де Арруда Падилья (Thiago de Arruda Padilha), который создал проект Neovim — обновлённую и улучшенную версию Vim для 21 века.



В рамках проекта Neovim планируется осуществить агрессивный рефакторинг исходного кода Vim. Цели:



  1. Упростить поддержку и увеличить скорость добавления патчей и новых функций;

  2. Распределить работу между несколькими разработчиками;

  3. Внедрить современный GUI как опцию;

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




Разработчик отмечает, что не ставит цель переписать Vim с нуля и создать IDE, хотя Neovim и имеет некоторые черты IDE. Напротив, изменения не должны сильно изменить модель работы Vim или vimscript в целом. Большинство плагинов vimscript продолжат нормально работать.

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


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



plugin -> neovim: {"id": 1, "method": "listenEvent", "params": {"eventName": "keyPressed"}}
neovim -> plugin: {"id": 1, "result": true}
neovim -> plugin: {"method": "event", "params": {"name": "keyPressed", "eventArgs": {"keys": ["C"]}}}
neovim -> plugin: {"method": "event", "params": {"name": "keyPressed", "eventArgs": {"keys": ["Ctrl", "Space"]}}}
plugin -> neovim: {"id": 2, "method": "showPopup", "params": {"size": {"width": 10, "height": 2} "position": {"column": 2, "line": 3}, "items": ["Completion1", "Completion2"]}}
plugin -> neovim: {"id": 2, "result": true}}




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

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



Программа GUI
|
---> Neovim
|
---> Плагин 1
|
---> Плагин 2
|
---> Плагин 3




Гипотетическая сессия GUI.

gui -> vim: {"id": 1, "method": "initClient", "params": {"size": {"rows": 20, "columns": 25}}}
vim -> gui: {"id": 1, "result": {"clientId": 1}}
vim -> gui: {"method": "redraw", "params": {"clientId": 1, "lines": {"5": " Welcome to neovim! "}}}
gui -> vim: {"id": 2, "method": "keyPress", "params": {"keys": ["H", "e", "l", "l", "o"]}}
vim -> gui: {"method": "redraw", "params": {"clientId": 1, "lines": {"1": "Hello ", "5": " "}}}




Таким образом, в редактор можно внедрить современные GUI, написанные на высокоуровневых языках программирования и лучше интегрированные в операционную систему. Плагины смогут взаимодействовать напрямую с GUI, как minimap в Sublime. Ядро редактора можно будет запустить на сервере, а много инстансов GUI — на клиентских машинах. Редактор можно будет встроить в другие программы, также как он фактически встроен в GUI.

Всю разработку Neovim планируется вести на Github. Принимаются пожертвования.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Подключаем к PSP геймпад от Xbox 360 при помощи Raspberry Pi

… или сказ про то, как пингвин Америку с Японией подружил.


Итак, в стародавние времена люди играли в Sony Playstation и их все устраивало. Но прогресс не стоял на месте. Увеличивалась степень интеграции микросхем. Инженерная мысль постоянно искала новые формфакторы, а мысль маркетинговая — новые рынки сбыта. Так в 2005 году появилась в продаже за пределами Японии портативная игровая система Sony Playstation Portable. Ее игровая линейка (как и у любой другой приставки) представляла собою специально скомпилированные под железо PSP игры. Но также она обладала и достаточными вычислительными мощностями для запуска игр от оригинальной PlayStation через встроенный эмулятор. Хотя, быть может, тут ключевую роль сыграло то, что и у PlayStation, и у PSP стоял процессор одной и той же архитектуры — а именно MIPS. Но самое примечательное в этой системе то, что сразу же, в год запуска, в сеть утекли библиотеки PSP SDK. В результате, через почти 10 лет с момента запуска, мы имеем огромную библиотеку игр и отлаженного homebrew. Также, сейчас, в не самом крупном городе России полностью рабочую PSP (самой функциональной модификации) можно купить с рук за 3000 рублей. Все это делает ее к настоящему моменту очень привлекательной бюджетной игровой системой с просто огромной инсталлбазой. Самая функциональная модификация имеет компонентный выход для подключения к ТВ. Но разъем подключения к ТВ располагается неудачно с точки зрения долгого использования PSP в качестве геймпада. К тому же, при длительном использовании возникает необходимость подключения второго провода — от зарядного устройства. И удобство использования такой химеры стремится к нулю. Как относительно бюджетно и при этом гиково решить эту проблемку — про это и пойдет речь в этой статье. Также вкратце будут затронуты темы программирования драйвера USB-клиента под PSP, методика установки хук-функций в PSP, работа под линуксом с устройствами USB и с джойстиками через API. Мы начинаем.


Идея подключения портативной консоли к ТВ не нова




Но прежде чем начнем, расскажу об одном интересном факте. Поскольку PSP вышла почти 10 лет назад, то на данный момент актуальным является следующее поколение портативных консолей от Sony, а именно Sony Playstation Vita. И дело в том, что в Японии вышла стационарная версия портативной консоли. Sony PlayStation Vita TV.

PS Vita TV





В качестве геймпадов она использует обычные Dualshock 3 от Playstation 3. Поддеживается USB или Bluetooth подключение. Vita TV, как и Vita, может воспроизводить игры от Vita, PSP и от оригинальной Playstation. Таким образом, идея «стационарной портативной» консоли достаточно состоятельна и интересна.

С помощью чего подружить геймпад и PSP?




Далее возник вопрос, как подключить внешний геймпад к PSP. Казалось бы, PSP имеет разъем USB, через который энтузиасты научили PSP запускать игры из папки подключенного компьютера или передавать всю картинку с игрой в окно этого самого подключенного по USB компьютера. Но, как оказалось, USB в PSP может быть только клиентом. И даже официальные аксессуары (например камера) работают в режиме хоста (кстати гугл при работе с периферией в андроид рекомендует переводить смартфон также в режим клиента). Т.е. подключать геймпад к PSP напрямую бесполезно. Поэтому нужно какое-то промежуточное устройство. В местном радиоэлектронном магазине отладочные платы разной степени крутизны стоили от 1 до 10 тысяч рублей. При том что это микроконтроллеры, и о USB-хосте нужно думать отдельно. Тут на глаза попался Raspberry Pi.

Raspberry Pi





В этой машинке есть все, что нужно — 2 USB порта, а также полноценный Linux. В не самом крупном городе России старшая модель (с 512 Мб памяти и Ethernet) стоит 1500 рублей через доски бесплатных частных объявлений. Цена соизмерима с самыми дешевыми контролерными отладочными платами, а функциональность не в пример больше. Причем еще и «Made in the UK».

Начало исследования




Если просто подключить USB-кабель в PSP, то она станет видна как флешка. Нам же нужно, чтобы она принимала команды о внешнем управлении. Т.е. в PSP должен крутиться какой-то код, который будет принимать информацию по USB, и имитировать нажатие органов управления на самом PSP. Сама возможность запуска какого-то кода помимо лицензионных игр возможна только на пиратских прошивках. Технически пиратская прошивка — это программа, прикидывающаяся официальной программой, располагающейся на карте памяти, и которая при запуске подменяет в оперативной памяти рабочий код прошивки на модифицированный, позволяющий запускать игры из .iso-файлов с карты памяти PSP. Таким образом, прошивка работает ровно до следующей перезагрузки PSP. Но нам важно не это, а то, что она поддерживает плагины. Плагины — это объектные файлы, слинкованные в определенном формате, которые стартуют в отдельных потоках параллельно запуску главного меню, игр PSP или игр оригинальной Playstation. Последней версией оригинальной прошивки PSP является аж 6.60. Плагины, заточенные под более ранние версии прошивки могут не работать под последней прошивкой. Так произошло и в данном случае. Плагин, который умеет пересылать по USB от PSP к ПК под управлением Windows видео всего, что происходит на PSP и принимать данные от геймпада, подключенного к ПК в PSP, по USB, на прошивке 6.60 работал только наполовину, т.е. данные от геймпада до PSP доходили, но имитация управления органами управления PSP не работала. Я начал искать плагины, которые так или иначе работают с управлением именно на прошивке 6.60. И нашел. Другой плагин служит для работы с аналоговым стиком PSP, и он работает на последней прошивке. Все исходники для PSP компилируются вот этим homebrew SDK.

Модификация исходников плагинов PSP. Хуки.




За основу проекта плагина, который я буду модифицировать, я выбрал тот, что уже содержал работащий код USB-клиента. Но для привычной отладки и вообще уютной атмосферы мне понадобился printf(). На PSP. В выбранном плагине его не было. Зато в плагине, из которого я хотел вытащить рабочий код перехвата событий органов управления PSP он был, выполненный через перехват функции отрисовки очередного кадра в кадровый буфер и дорисовки к кадру нужных мне отладочных строк. Сам перехват функции (хук) отрисовки реализован следующим образом:

#define GET_JUMP_TARGET_(x) (0x80000000 | (((x) & 0x03FFFFFF) << 2))
int (*g_setframebuf)(int unk, void* addr, int width, int psm, int sync);
int setframebuf_hook_func(int unk, void* addr, int width, int psm, int sync)
{
if(g_info == 1)
{
dbgprint( debugmsg, addr, psm );
if (!g_info) DEBUG_RESET()
}

return g_setframebuf(unk, addr, width, psm, sync);
}

int hook_function(unsigned int* jump, void* hook, unsigned int* result)
{
unsigned int target;
unsigned int func;
int inst;

target = GET_JUMP_TARGET_(*jump);
while (((inst = _lw(target+4)) & ~0x03FFFFFF) != 0x0C000000) // search next JAL instruction
target += 4;

if((inst & ~0x03FFFFFF) != 0x0C000000)
{
printf("invalid!\n");
return 1;
}

*result = GET_JUMP_TARGET_(inst);
func = (unsigned int) hook;
func = (func & 0x0FFFFFFF) >> 2;
_sw(0x0C000000 | func, target+4);

return 0;
}

int module_start( SceSize args, void *argp )
{
//...
hook_function( (unsigned int*) sceDisplaySetFrameBuf, setframebuf_hook_func, (unsigned int*)&g_setframebuf );
//...
}




После вызова hook_function() операционная система PSP при вызове своей внутренней функции ядра sceDisplaySetFrameBuf() будет фактически вызывать setframebuf_hook_func(). А для вызова оригинальной sceDisplaySetFrameBuf() нужно теперь вызывать g_setframebuf(). Кому интересна тема хуков, более подробно можно почитать например здесь.

Модификация исходников плагинов PSP. Управление.




Далее я добавил в модифицируемый проект рабочие хуки на функции управления sceCtrlReadBufferPositive(), sceCtrlPeekBufferPositive(), sceCtrlReadBufferNegative() и sceCtrlPeekBufferNegative(), взяв их из того же JoySens. Только сделал так, чтобы входными данными внутри них были последние присланные в PSP данные о состоянии геймпада, подключенного к ПК-хосту. Вот архив со всеми нужными бинарниками и исходниками. Перед запуском ПК-части программы нужно установить драйвера USB. Сначала нужно запустить плагин на PSP (как запустить плагин можно узнать, погуглив в яндексе). Потом перезагрузить PSP и подключить ее к ПК. Должно обнаружиться устройство PSP Type B. Далее скачиваем драйвера. Устанавливаем драйвера через мастер (bin\inf-wizard.exe), указывая наше устройство PSP Type B и говоря в конце установить драйвер.

Подготовка минимальной версии PSP-части




Все бы хорошо, но в сети есть исходники только на версию 0.19 RemoteJoyLite. А она некорректно работает на некоторых играх (например K-On! дико тормозит, а в Dungeon Siege появляются графические артефакты). В версии 0.20 это, как говорят, исправили, но исходников этой версии в открытом доступе нет. Поэтому было решено модифицировать протокол данных, передающихся по USB, чтобы передавать только минимум информации о состоянии геймпада, а также минимизировать размер исходника PSP-части. Из протокола были удалены все данные, передающиеся от PSP в ПК, и оставлена только одна структура, передающаяся от ПК в PSP, в результате чего тормоза и артефакты канули в небытие:

#define USBDATA_PATTERN 0x1234ABFE
struct
{
unsigned int Pattern;
unsigned int ButtonData;
unsigned int AnalogX;
unsigned int AnalogY;
} PSPUsbData;




Аналоговые данные со стика в самой PSP представлены в виде однобайтового беззнакового целого для каждой оси (127 — центр), а 4 байта в протоколе выделено из-за желания даже не думать про проблемы упаковывания и выравнивания структур, т.к. в самом RemoteJoyLite данные упаковываются следующим образом:

struct HostFsCmd
{
uint32_t magic;
uint32_t command;
uint32_t extralen;
} __attribute__((packed));




И чтобы даже не задумываться о соответствующих проблемах (ведь сам RemoteJoyLite компилируется MinGW GCC, а следующим шагом будет создание проекта в Microsoft Visual Studio для отработки урезанного протокола, которая про __attribute__((packed)) не знает), я убрал все выравнивания и упаковывания структур, приведя их к 32-битному представлению. В итоге, в этом архиве содержатся исходники и бинарники урезанного проекта — и PSP-, и Windows-часть. Windows-приложение выполнено в виде проекта mfc на C++ для Microsoft Visual Studio 2010. Изучающим Windows-программирование будет полезно посмотреть, как реализована обработка нажатий клавиш управления курсором (в mfc-приложениях оно работает, только если находится в фильтре оконных сообщений всего приложения, а не в диалоговом обработчике нажатия клавиш), а также за счет чего корректно работает printf() на форму даже из отдельного потока. В части же PSP будет интересно изучить прилагающийся легковесный исходник, в котором оставлены только USB, управление и printf(). Например, прием данных по USB асинхронен и реализован следующим образом. При подключении к USB-хосту, после корректной процедуры получения внутреннего адреса на шине USB (см. описание USB) происходит вызов UsbAttach(), поскольку в зарегистрированной при инициализации структуре драйвера был описан этот вызов:

#define RJLITE_DRIVERNAME "RJLiteDriver"
#define RJLITE_DRIVERPID (0x1C9)
struct UsbDriver UsbDriver = {
RJLITE_DRIVERNAME,
4,
UsbEndpoint,
&UsbInterface,
&UsbData[0].devdesc[0],
&UsbData[0].config,
&UsbData[1].devdesc[0],
&UsbData[1].config,
&StringDescriptor,
UsbRequest,
UsbUnknown,
UsbAttach,
UsbDetach,
0,
UsbStartFunc,
UsbStopFunc,
NULL
};

int module_start( SceSize args, void *argp )
{
//...
sceUsbbdRegister(&UsbDriver);
if((sceUsbStart(PSP_USBBUS_DRIVERNAME, 0, 0) == 0) && (sceUsbStart(RJLITE_DRIVERNAME, 0, 0) == 0) && //...
{
//...
}
//...
}




Где module_start() — функция, вызываемая в отдельном потоке при запуске плагина пиратской прошивкой. Также при запуске драйвера происходит создание флаговой переменной типа int (т.е. 32 флага) с доступом через уникальный идентификатор объекта в операционной системе PSP и запуск вспомогательного потока:

static SceUID UsbMainEventFlag = -1;
static int UsbStartFunc( int size, void *p )
{
//...
UsbMainEventFlag = sceKernelCreateEventFlag( "USBMainEvent", 0x200, 0, NULL );
//...
UsbMainThreadID = sceKernelCreateThread( "USBMainThread", UsbMainThread, 10, 0x10000, 0, NULL );
//...
sceKernelStartThread( UsbMainThreadID, 0, NULL );
//...
}




Так вот, а вызываемый UsbAttach() устанавливает флаг USB_EVENT_ATTACH во флаговой переменной объекта UsbMainEventFlag:

static int UsbAttach(int speed, void *arg2, void *arg3)
{
sceKernelSetEventFlag( UsbMainEventFlag, USB_EVENT_ATTACH);
return 0;
}




При этом в предварительно созданном при вызове UsbStartFunc() потоке UsbMainThread() написано:

static int UsbMainThread(SceSize size, void *argp)
{
int ret;
u32 result;

while(1)
{
ret = sceKernelWaitEventFlag(UsbMainEventFlag, USB_EVENT_ATTACH | USB_EVENT_ASYNC, PSP_EVENT_WAITOR | PSP_EVENT_WAITCLEAR, &result, NULL);
if(ret < 0)
{
sceKernelExitDeleteThread(0);
}

if(result&USB_EVENT_ASYNC)
{
usb_async_events++;//nyashkoshkko: debug
SetUsbAyncReq(&PSPUsbData, sizeof(PSPUsbData));
}

if(result&USB_EVENT_ATTACH)
{
usb_attach_events++;//nyashkoshkko: debug
SetUsbAyncReq(&PSPUsbData, sizeof(PSPUsbData));
}
}
return 0;
}




А это значит, что поток в бесконечном цикле ждет установки флага USB_EVENT_ATTACH или флага USB_EVENT_ASYNC во флаговой переменной объекта UsbMainEventFlag. Успешная установка связи с USB-хостом вызвала установку флага USB_EVENT_ATTACH, по которому этот поток выполняет асинхронный запрос на прием пакета данных по USB, при этом сбрасывая флаг USB_EVENT_ASYNC:

static int SetUsbAyncReq( void *data, int size )
{
//...
UsbAsyncReq.data = data;
UsbAsyncReq.size = size;
UsbAsyncReq.func = UsbAsyncReqDone;
sceKernelClearEventFlag( UsbMainEventFlag, ~USB_EVENT_ASYNC );
return( sceUsbbdReqRecv( &UsbAsyncReq ) );
}




В этом запросе callback-ом устанавливается вызов функции UsbAsyncReqDone():

static int UsbAsyncReqDone( struct UsbdDeviceReq *req, int arg2, int arg3 )
{
sceKernelSetEventFlag( UsbMainEventFlag, USB_EVENT_ASYNC );
return( 0 );
}




Эта функция, как мы видим, по завершению приема пакета данных от USB-хоста (обрабатываемого ядром операционной системы PSP по прерыванию от USB-контроллера PSP) выставляет флаг USB_EVENT_ASYNC во флаговой переменной объекта UsbMainEventFlag. По нему наш бесконечный цикл выставляет новый асинхронный запрос данных. Такой механизм событий позволяет не тратить процессорное время впустую на бесконечный опрос флага готовности данных, поскольку при вызове sceKernelWaitEventFlag() потоку не выделяются кванты времени до тех пор, пока не наступит необходимое событие — это обеспечивает планировщик потоков внутри операционной системы PSP, да и вообще этот базовый принцип работает в любой многозадачной операционной системе.

Написание сервиса для работы с USB для Linux под Raspberry Pi




Итак, PSP-часть завершена. Теперь время для разработки приложения, а точнее сервиса, который будет запускаться автоматически при включении Raspberry Pi под Linux. Вообще, для Raspberry Pi существует несколько адаптированных дистрибутивов Linux. Но я остановился на Fedora, т.к. он черпает свои корни от Red Hat, с которым я банально имел дело по работе и привык к его RPM дистрибуции пакетов. Сразу после установки Fedora Remix 18 и, в случае необходимости, настройки сети (в моем случае нужно было руками прописать сетевой адрес и шлюз, т.к. DHCP-сервер в домашней сети работает некорректно), которая делается интуитивно — подключив мышь и кликнув на значок сетевого соединения в правом верхнем углу, прямо из коробки работает SSH-сервер. А вот SMB-сервер оперативно настроить не удалось (проблемы с smbpasswd), поэтому исходник создавался и редактировался удаленно по SSH через midnight commander. Первое, с чего я начал, это подключение к PSP. Для этого нужно было узнать, как в Linux взаимодействовать с USB. В связи с этим произошла небольшая неприятная история, из-за которой, в очередной раз, у меня перед глазами рушится весь шарм линукса. Дело в том, что при попытке установить библиотеку и заголовочник для компиляции через

> yum install libusb1-devel




менеджер пакетов поругался и сказал что он устарел, используй libusbx. Хорошо, команда

> yum install libusbx-devel




скачала необходимые файлы. Но дело то в том, что libusbx по api-вызовам несовместим с libusb1, который одинаков с windows-версией libusb, которая, в свою очередь, использовалась в оригинальных исходниках RemoteJoyLite, да и вообще отлично работает под Windows. Но, ладно. С usb разобрались, теперь перейдем к доступу к геймпаду из под линукс. У меня в распоряжении есть проводной геймпад от Xbox 360, который отлично чувствует себя в Windows, и, на удивление, заработал из коробки в Fedora Remix 18 на Raspberry Pi, создав устройство /dev/input/js0. Это отработал штатный драйвер xpad. Существует альтернативный драйвер xboxdrv — он более гибок в конфигурировании. Но нам хватит и штатного.

Кстати, у андроида дела обстоят точно так же.
Драйвер xpad входит в состав ядра Linux для андроида:

#define DRIVER_DESC "X-Box pad driver"




И точно так же создается устройство /dev/input/js0:

MODULE_SUPPORTED_DEVICE("input/js");




Например рассмотрим, как происходит получение списка устройств ввода в андроиде. Рекомендуемое api говорит нам для этого вызвать getDeviceIds(), в котором написано:

/**
* Gets the ids of all input devices in the system.
* @return The input device ids.
*/
public static int[] getDeviceIds() {
return InputManager.getInstance().getInputDeviceIds();
}




getInputDeviceIds():

private final IInputManager mIm;

//...

private SparseArray<InputDevice> mInputDevices;

//...

/**
* Gets the ids of all input devices in the system.
* @return The input device ids.
*/
public int[] getInputDeviceIds() {
synchronized (mInputDevicesLock) {
populateInputDevicesLocked();

final int count = mInputDevices.size();
final int[] ids = new int[count];
for (int i = 0; i < count; i++) {
ids[i] = mInputDevices.keyAt(i);
}
return ids;
}
}

//...

private void populateInputDevicesLocked() {
if (mInputDevicesChangedListener == null) {
final InputDevicesChangedListener listener = new InputDevicesChangedListener();
try {
mIm.registerInputDevicesChangedListener(listener);
} catch (RemoteException ex) {
throw new RuntimeException(
"Could not get register input device changed listener", ex);
}
mInputDevicesChangedListener = listener;
}

if (mInputDevices == null) {
final int[] ids;
try {
ids = mIm.getInputDeviceIds();
} catch (RemoteException ex) {
throw new RuntimeException("Could not get input device ids.", ex);
}

mInputDevices = new SparseArray<InputDevice>();
for (int i = 0; i < ids.length; i++) {
mInputDevices.put(ids[i], null);
}
}
}




mIm.getInputDeviceIds():

interface IInputManager {
// Gets input device information.
InputDevice getInputDevice(int deviceId);
int[] getInputDeviceIds();
//...




Тут вступает в дело сервис InputManager:

import android.view.InputDevice;

//...

/*
* Wraps the C++ InputManager and provides its callbacks.
*/
public class InputManagerService extends IInputManager.Stub
implements Watchdog.Monitor, DisplayManagerService.InputManagerFuncs {
static final String TAG = "InputManager";
static final boolean DEBUG = false;

private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";

//...

private InputDevice[] mInputDevices = new InputDevice[0];

//...

/**
* Gets the ids of all input devices in the system.
* @return The input device ids.
*/
@Override // Binder call
public int[] getInputDeviceIds() {
synchronized (mInputDevicesLock) {
final int count = mInputDevices.length;
int[] ids = new int[count];
for (int i = 0; i < count; i++) {
ids[i] = mInputDevices[i].getId();
}
return ids;
}
}




getId() приводит нас уже туда, где мы были (андроид удивителен):

public final class InputDevice implements Parcelable {
private final int mId;

//...

/**
* Gets the input device id.
* <p>
* Each input device receives a unique id when it is first configured
* by the system. The input device id may change when the system is restarted or if the
* input device is disconnected, reconnected or reconfigured at any time.
* If you require a stable identifier for a device that persists across
* boots and reconfigurations, use {@link #getDescriptor()}.
* </p>
*
* @return The input device id.
*/
public int getId() {
return mId;
}

//...

// Called by native code.
private InputDevice(int id, int generation, int controllerNumber, String name, int vendorId,
int productId, String descriptor, boolean isExternal, int sources, int keyboardType,
KeyCharacterMap keyCharacterMap, boolean hasVibrator, boolean hasButtonUnderPad) {
mId = id;
mGeneration = generation;
mControllerNumber = controllerNumber;
mName = name;
mVendorId = vendorId;
mProductId = productId;
mDescriptor = descriptor;
mIsExternal = isExternal;
mSources = sources;
mKeyboardType = keyboardType;
mKeyCharacterMap = keyCharacterMap;
mHasVibrator = hasVibrator;
mHasButtonUnderPad = hasButtonUnderPad;
}

private InputDevice(Parcel in) {
mId = in.readInt();
mGeneration = in.readInt();
mControllerNumber = in.readInt();
mName = in.readString();
mVendorId = in.readInt();
mProductId = in.readInt();
mDescriptor = in.readString();
mIsExternal = in.readInt() != 0;
mSources = in.readInt();
mKeyboardType = in.readInt();
mKeyCharacterMap = KeyCharacterMap.CREATOR.createFromParcel(in);
mHasVibrator = in.readInt() != 0;
mHasButtonUnderPad = in.readInt() != 0;

for (;;) {
int axis = in.readInt();
if (axis < 0) {
break;
}
addMotionRange(axis, in.readInt(), in.readFloat(), in.readFloat(), in.readFloat(),
in.readFloat(), in.readFloat());
}
}




В нативной части андроида экземпляр InputDevice() создается здесь (спасибо оперативному ответу с тостера):

jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& deviceInfo) {

//...

ScopedLocalRef<jobject> inputDeviceObj(env, env->NewObject(gInputDeviceClassInfo.clazz,
gInputDeviceClassInfo.ctor, deviceInfo.getId(), deviceInfo.getGeneration(),
deviceInfo.getControllerNumber(), nameObj.get(),
static_cast<int32_t>(ident.vendor), static_cast<int32_t>(ident.product),
descriptorObj.get(), deviceInfo.isExternal(), deviceInfo.getSources(),
deviceInfo.getKeyboardType(), kcmObj.get(), deviceInfo.hasVibrator(),
deviceInfo.hasButtonUnderPad()));




Эта функция вызывается здесь:

void NativeInputManager::notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) {
JNIEnv* env = jniEnv();

//...
jobject inputDeviceObj = android_view_InputDevice_create(env, inputDevices.itemAt(i));




Вызов функции notifyInputDevicesChanged() определен колбэком опять в уже знакомом сервисе InputManager:

// Native callback.
private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
synchronized (mInputDevicesLock) {
if (!mInputDevicesChangedPending) {
mInputDevicesChangedPending = true;
mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
mInputDevices).sendToTarget();
}

mInputDevices = inputDevices;
}
}




Вызов самого колбэка инициируется в InputReader:

void InputReader::loopOnce() {

//...

size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

//...

// Send out a message that the describes the changed input devices.
if (inputDevicesChanged) {
mPolicy->notifyInputDevicesChanged(inputDevices);
}




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

sp<EventHubInterface> mEventHub;




И, в итоге, в реализации этого класса EventHub.cpp идет открытие и работа с устройством из /dev/input, как и в обычном Linux Fedora в Raspberry Pi:

static const char *DEVICE_PATH = "/dev/input";

//...

char devname[PATH_MAX];
char *filename;

//...

strcpy(devname, DEVICE_PATH);
filename = devname + strlen(devname);
*filename++ = '/';

//...

strcpy(filename, event->name);

//...

openDeviceLocked(devname);

//...

status_t EventHub::openDeviceLocked(const char *devicePath) {
char buffer[80];

ALOGV("Opening device: %s", devicePath);

int fd = open(devicePath, O_RDWR | O_CLOEXEC);
if(fd < 0) {
ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
return -1;
}




А вообще, про всю эту систему ввода в андроиде вкратце объяснено в самих исходниках здесь:

/*
* The input manager is the core of the system event processing.
*
* The input manager uses two threads.
*
* 1. The InputReaderThread (called "InputReader") reads and preprocesses raw input events,
* applies policy, and posts messages to a queue managed by the DispatcherThread.
* 2. The InputDispatcherThread (called "InputDispatcher") thread waits for new events on the
* queue and asynchronously dispatches them to applications.
*
* By design, the InputReaderThread class and InputDispatcherThread class do not share any
* internal state. Moreover, all communication is done one way from the InputReaderThread
* into the InputDispatcherThread and never the reverse. Both classes may interact with the
* InputDispatchPolicy, however.
*
* The InputManager class never makes any calls into Java itself. Instead, the
* InputDispatchPolicy is responsible for performing all external interactions with the
* system, including calling DVM services.
*/
class InputManagerInterface : public virtual RefBase {





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

#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <libusb-1.0/libusb.h>

#define SONY_VENDOR_ID 0x054C
#define PSP_B_PRODUCT_ID 0x01C9

#define UP 0x00000010
#define DOWN 0x00000040
#define LEFT 0x00000080
#define RIGHT 0x00000020
#define B_X 0x00004000
#define B_O 0x00002000
#define B_KVADRAT 0x00008000
#define B_TREUGOLNIK 0x00001000
#define B_L 0x00000100
#define B_R 0x00000200
#define B_SELECT 0x00000001
#define B_START 0x00000008
#define B_NOTE 0x00800000

struct
{
unsigned int Pattern;
unsigned int Btn;
unsigned int X;
unsigned int Y;
} PS = {0x1234ABFE, 0, 127, 127};

struct js_event
{
unsigned int time;
short value;
unsigned char type;
unsigned char number;
};

int is_usbdevblock(libusb_device *dev)
{
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if((desc.idVendor == SONY_VENDOR_ID) && (desc.idProduct == PSP_B_PRODUCT_ID))
{
return 1;
}

return 0;
}

int main(int argc, char** argv)
{
unsigned int real_x = 0, real_y = 0;
int x, y;

int fd = 0;

while(1)
{
libusb_device **list;
libusb_device *found = NULL;
libusb_context *ctx = NULL;
int attached = 0;

libusb_init(&ctx);
libusb_set_debug(ctx, 3);

ssize_t cnt = libusb_get_device_list(ctx, &list);
ssize_t i = 0;
int err = 0;
if(cnt < 0)
{
return -1;
}

for(i = 0; i < cnt; i++)
{
libusb_device *device = list[i];
if(is_usbdevblock(device))
{
found = device;
break;
}
}

if(found)
{
libusb_device_handle *handle;
err = libusb_open(found, &handle);
if (err)
{
return -1;
}

if (libusb_kernel_driver_active(handle, 0))
{
libusb_detach_kernel_driver(handle, 0);
attached = 1;
}

err = libusb_claim_interface(handle, 0);
if (err)
{
return -1;
}

if(fd == 0)
{
fd = open("/dev/input/js0", O_RDONLY);
}

if(fd < 0)
{
goto clean;
}

int nEndpoint = 0x01;
int nTimeout = 500; //in milliseconds
int BytesWritten = 0;
int ret;

struct js_event e;
int t;

while(1)
{
read(fd, &e, sizeof(struct js_event));

e.type &= ~0x80;

t = 0; //transfer = 0;

if(e.type == 1)
{
if(e.value == 1)
{
if(e.number == 0) {PS.Btn |= B_X; t = 1;}
if(e.number == 1) {PS.Btn |= B_O; t = 1;}
if(e.number == 2) {PS.Btn |= B_KVADRAT; t = 1;}
if(e.number == 3) {PS.Btn |= B_TREUGOLNIK; t = 1;}
if(e.number == 4) {PS.Btn |= B_L; t = 1;}
if(e.number == 5) {PS.Btn |= B_R; t = 1;}
if(e.number == 6) {PS.Btn |= B_SELECT; t = 1;}
if(e.number == 7) {PS.Btn |= B_START; t = 1;}
if(e.number == 8) {PS.Btn |= B_NOTE; t = 1;}//XBOX_HOME
//if(e.number == 9) PS.Btn |= ;//L_STICK_PRESS
//if(e.number == 10)PS.Btn |= ;//R_STICK_PRESS
}

if(e.value == 0)
{
if(e.number == 0) {PS.Btn &= ~B_X; t = 1;}
if(e.number == 1) {PS.Btn &= ~B_O; t = 1;}
if(e.number == 2) {PS.Btn &= ~B_KVADRAT; t = 1;}
if(e.number == 3) {PS.Btn &= ~B_TREUGOLNIK; t = 1;}
if(e.number == 4) {PS.Btn &= ~B_L; t = 1;}
if(e.number == 5) {PS.Btn &= ~B_R; t = 1;}
if(e.number == 6) {PS.Btn &= ~B_SELECT; t = 1;}
if(e.number == 7) {PS.Btn &= ~B_START; t = 1;}
if(e.number == 8) {PS.Btn &= ~B_NOTE; t = 1;}
}
}

if(e.type == 2)
{
if(e.number == 6)
{
if(e.value == -32767) {PS.Btn |= LEFT; t = 1;}
if(e.value == 32767) {PS.Btn |= RIGHT; t = 1;}
if(e.value == 0) {PS.Btn &= ~(LEFT | RIGHT); t = 1;}
}
if(e.number == 7)
{
if(e.value == -32767) {PS.Btn |= UP; t = 1;}
if(e.value == 32767) {PS.Btn |= DOWN; t = 1;}
if(e.value == 0) {PS.Btn &= ~(UP | DOWN); t = 1;}
}
if(e.number == 0)
{
if(real_x != ((e.value + 32767) / 256)) {real_x = ((e.value + 32767) / 256); t = 1;}
}
if(e.number == 1)
{
if(real_y != ((e.value + 32767) / 256)) {real_y = ((e.value + 32767) / 256); t = 1;}
}
}

if(t == 1)
{
#define KOEF 1.4
//[-128..0..127]
x = real_x - 128;
y = real_y - 128;
x = x * (1. + ((abs(x) * (KOEF-1.))/(127./KOEF))); if(x > 127) x = 127; if(x < -128) x = -128;
y = y * (1. + ((abs(y) * (KOEF-1.))/(127./KOEF))); if(y > 127) y = 127; if(y < -128) y = -128;
PS.X = 128 + x;
PS.Y = 128 + y;

ret = libusb_bulk_transfer(handle, nEndpoint, (unsigned char *)&PS, sizeof(PS), &BytesWritten, nTimeout);
if(ret < 0)
{
break;
}
}
}

clean:

if(fd)
{
close(fd);
fd = 0;
}

if(attached == 1)
{
libusb_attach_kernel_driver(handle, 0);
}

libusb_close(handle);
}

libusb_free_device_list(list, 1);
libusb_exit(ctx);

sleep(1);
}

return 0;
}




Вот ссылка на двоичный файл сервиса. А вот также содержимое скрипта компиляции m.sh:

gcc xbox2psp.c -o xbox2psp.o -I/usr/local -L/usr/local -lusb-1.0




По самому исходнику хотелось бы отметить два момента. Во-первых, аналоговые стики Xbox имеют точность 16 бит, в то время как стик PSP имеет точность 8 бит. В связи с этим пакет я шлю по изменению приведенного к 8 битам значения осей, а не по изменению исходных данных от контроллера Xbox. Во-вторых, в PSP значение диагоналей соответствует полной шкале (т.е. круглый стик PSP с точки зрения шкалы — это квадрат), а в Xbox, как и положено, половине шкалы:


Поэтому введен линейно увеличивающийся (чем больше отклонение от центра оси контроллера Xbox, тем больше) коэффициент с максимумом в 1.4 (хотя, как выяснилось позже, правильно было бы определять значение угла, и чем ближе угол к диагонали, тем больше делать коэффициент). С этими значениями геймпад Xbox ощущается без какого то ни было дискомфорта, хоть чисто технически чувствительность и получилась загрубленной. В Doom 0.05 управлять удобно, в Dungeon Siege все три скорости перемещения (в зависимости от силы отклонения стика) работают и ощущаются как на самой PSP. Ибо, при столкновении с проблемой, в начале был опробован простой коэффициент (и 1.5, и 1.4), без линейного увеличения в зависимости от отклонения, и в названных играх ощущался резкий дискомфорт — играть было невозможно.


Добавление собственного сервиса в автозагрузку в Fedora Remix 18 для Raspberry Pi




Поверхностное гугление по вопросу добавления программы в автозагрузку в Linux дает в основном рекомендации по модификации скрипта init rc. Но в нашем случае нужно поступить по-другому.

1. Сначала нужно скопировать наш сервис xbox2psp.o в /usr/local/bin и установить ему права запуска(все три бита).


2. Затем создать файл /lib/systemd/system/xbox2psp.service следующего содержания:



[Unit]
Description=xbox2psp
After=syslog.target network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/xbox2psp.o

[Install]
WantedBy=multi-user.target




3. Перейти в папку /etc/systemd/system/ и создать ссылку командой

> ln -s /lib/systemd/system/xbox2psp.service xbox2psp.service




4. Перезагрузить конфигурацию демона автозагрузки:

> systemctl daemon-reload




5. Активировать автозапуск нового сервиса

> systemctl enable xbox2psp.service




6. При необходимости можно сразу запустить сервис командой

> systemctl start xbox2psp.service




В итоге мы получили удобную возможность управлять PSP при помощи геймпада от Xbox 360. При желании этот проект можно модифицировать для подключения например Dualshock 3 по Bluetooth.

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.