-Поиск по дневнику

Поиск сообщений в rss_rss_hh_new

 -Подписка по e-mail

 

 -Статистика

Статистика LiveInternet.ru: показано количество хитов и посетителей
Создан: 17.03.2011
Записей:
Комментариев:
Написано: 51

Habrahabr/New








Добавить любой RSS - источник (включая журнал LiveJournal) в свою ленту друзей вы можете на странице синдикации.

Исходная информация - http://habrahabr.ru/rss/new/.
Данный дневник сформирован из открытого RSS-источника по адресу http://feeds.feedburner.com/xtmb/hh-new-full, и дополняется в соответствии с дополнением данного источника. Он может не соответствовать содержимому оригинальной страницы. Трансляция создана автоматически по запросу читателей этой RSS ленты.
По всем вопросам о работе данного сервиса обращаться со страницы контактной информации.

[Обновить трансляцию]

«Как это работает»: Классификация ЦОД Tier

Вторник, 18 Июля 2017 г. 09:03 + в цитатник
В июне этого года было анонсировано сразу несколько важных событий в индустрии дата-центров. Для начала стало известно, что получено разрешение на строительство первого в Республике Бангладеш и единственного в своем роде в Азии национального ЦОДа категории Tier IV. Следом за этим японский технический гигант Fujitsu объявил о глобальной модернизации своих австралийских дата-центров — тоже до уровня Tier IV. Последние новости дали почву для размышлений об эволюции ЦОДов и сути их классификации, о чем сегодня мы и поговорим.

/ фото Arthur Caranta CC

Классификация Uptime Institute


У клиентов операторов дата-центров всегда были определенные ожидания и требования к предоставляемой инфраструктуре. В основном речь шла о надежности и безопасности — самых значимых показателях при выборе центра обработки данных. Вехой в становлении стандартизации стало объединение в 1989 году единомышленников в группу Uninterruptible Uptime Users Group (UUUG). По словам Эдварда Рафтера (Edward Rafter), инженера, проектировавшего ЦОДы на раннем этапе развития индустрии в США, это событие ознаменовало собой поворотный момент в обмене опытом и стало первым толчком к оценке инфраструктуры дата-центров.

В 1993 году организация Uptime Institute с помощью ассоциации компаний, ответственных за обслуживание наиболее важных ЦОДов в Америке, создала базу по обмену опытом. На ее основе начали вырабатываться способы оценки эффективности центров обработки данных. Были проанализированы аспекты, которые влияют на принятие бизнес-решений: около 30 факторов работоспособности дата-центров, относящихся к расположению, воздействию на окружающую среду и качеству обслуживания и 16 подсистем технического характера. На последних и было сосредоточено внимание Uptime Institute при разработке классификации. Она была оформлена в 1990-х в качестве стандартизованной методологии.

Uptime Institute обладает правами на сертификацию ЦОДов в соответствии с Tier-системой при проектировании, строительстве и эксплуатации инфраструктуры во всем мире. Дата-центры в России разрабатываются в соответствии с требованиями стандарта TIA-942 Ассоциации изготовителей оборудования для передачи данных (TIA) Института американских национальных стандартов. Требования TIA охватывают сферы строительства, электроснабжения, охлаждения, контроля безопасности, резервирования, ремонтопригодности и ввода в эксплуатацию.

Uptime Institute и внутренние ГОСТы используются в России как дополнения к стандартам TIA. Важно, что TIA-942, представленный в 2005 году, в свою очередь, основывается на стандарте Uptime Institute. Более того, между Uptime Institute и TIA достигнуто соглашение, в результате которого Ассоциация отказалась от использования в своей методологии термина Tier. Теперь он всецело связан с деятельностью Uptime Institute.

Если говорить о различиях двух подходов, стоит отметить, что система Uptime Institute не стремится обеспечивать жесткую техническую спецификацию того, как следует проектировать и строить ЦОДы. Стандарт TIA, напротив, диктует конкретные требования по ресурсам и доступности для каждого уровня. В отличие от Uptime Institute, TIA не имеет полномочий для проведения официальной процедуры оценки дата-центров. Также нет группы оценщиков, следящей за соблюдением стандартов. Однако конкретные требования к каждому уровню находятся в открытом доступе и не предусмотрено никакой платы за их использование. В противоположность этому Uptime Institute проводит платную сертификацию ЦОДов.

Известны четыре уровня стандарта Uptime Institute:

  • Tier I — базовая инфраструктура без резервирования;
  • Tier II — инфраструктура с резервными мощностями;
  • Tier III — инфраструктура, поддерживающая параллельный ремонт;
  • Tier IV — отказоустойчивая инфраструктура.

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

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

ЦОДы второго уровня включают в себя резервные возможности для критически важных компонентов в целях обеспечения ремонта и повышенной защиты IT-процессов от сбоев. Резервируемые системы включают в себя оборудование для питания и охлаждения, такие как источники бесперебойного питания, чиллеры или насосы, а также генераторы.


Центр обработки данных Tier III не требует прекращения работы оборудования для замены «железа» и обслуживания. К компонентам добавляется резервный канал питания и охлаждения так, чтобы каждый элемент, необходимый для поддержки IT-системы, можно было отключить, и это не сказалось на работе.

ЦОДы Tier IV в дополнение ко всем особенностям предыдущего уровня характеризуются повышенной (еще большей, чем у Tier III) отказоустойчивостью, то есть сбои отдельных элементов или перебои резервного канала не сказываются на IT-операциях.

Принято считать, что ожидаемый уровень безотказной работы дата-центра Tier I составляет 99,671% (1729 минут годового простоя); Tier 2 — 99,741% (1361 минут годового простоя); Tier III — 99,982% (95 минут годового простоя); Tier IV — 99,995% (26 минут годового простоя).

Зачем нужна классификация ЦОДов?


Uptime Institute принимает заявки операторов дата-центров на независимую оценку инфраструктуры. Это добровольная процедура, к которой прибегают не все компании. При этом, исходя из базовой идеи классификации, прозрачность в вопросе выбора ЦОДа — благо для клиентов. Поэтому, начиная с 2015 года, Uptime Institute принялся стимулировать операторов к прохождению сертификации.

Организация объявила о новом параметре оценки дата-центров — энергоэффективности. Предлагаются два уровня соответствия: «одобренный» и «активированный». Результат оценки, по мнению Uptime Institute, свидетельствует о передовом опыте компании в отрасли. Подтвержденная энергоэффективность дата-центра выступает дополнительным аргументом для выбора клиентами.

В целом классификация важна для клиента, так как она выступает гарантией соответствия ожиданиям конечного результата в вопросе безотказной работы и производительности. Джо Хертвик (Joe Hertvik), глава консалтинговой компании Hertvik Business Services, определяет несколько сценариев использования рейтинговой системы:

  1. Оценка рисков при передаче инфраструктуры облачному провайдеру.
  2. Настройка дата-центра с целью обеспечения его соответствия конкретным бизнес-потребностям.
  3. Предоставление сертификата клиентам в качестве дополнительного преимущества.
  4. Выбор уровня доступности сети при оценке рисков.

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

Какой Tier выбрать?


Существует распространенное заблуждение: уровень качества услуг дата-центров возрастает с каждым Tier. На самом деле, классификация ЦОДов не нацелена на то, чтобы определить лучший тип дата-центров. Каждый Tier предназначен для удовлетворения разнообразных бизнес-потребностей и требований к производительности. Различным предприятиям нужна различная инфраструктура, и для большинства организаций хостинг в центре Tier IV попросту неэффективен.

В 2013 году портал Data Center Dynamics опросил группу экспертов, чтобы выяснить, стоит ли переплачивать за переход на более высокий Tier. Раул Шеуол (Rahul Shewale), консультант в Capgemini, и доктор Карлос Гарсия де ла Ночеда (Dr Carlos Garcia de la Noceda) сошлись во мнении, что ЦОД Tier III может обладать более надежной инфраструктурой и быть более эффективным с экономической точки зрения, чем Tier IV. А Уильям Энгл (William Angle), директор CS Technology, участвовавший в создании первого в мире объекта Tier IV, полагает, что почти 60% всех сбоев происходит из-за людей, а не из-за инфраструктуры — поэтому не всегда есть смысл обращаться к максимальным конфигурациям.

Сотрудники Uptime Institute же сообщают, что расходы на инфраструктуру ЦОДов и операционные сложности возрастают от уровня к уровню, и владельцам следует выбирать Tier, который лучше соответствует потребностям конкретного бизнеса.

«Tier IV не всегда «лучше» решения Tier II. Инфраструктура центра обработки данных должна соответствовать коммерческому применению, иначе компании могут вложить чрезмерно большой капитал или взять на себя слишком большой риск», — говорится на сайте организации.

Если вспомнить последние новости, можно заметить, что стремление Бангладеша и Fujitsu к ЦОДам Tier IV объясняется климатическими и сейсмическими обстановками, но не лучшими характеристиками этих дата-центров в сравнении с другими. Строительство мега-ЦОДа власти Бангладеш анонсировали еще в 2014 году, и тогда же появилась информация о выборе под эти цели района, подверженного землетрясениям.

Представители Uptime Insitute заявили, что риски землетрясения не учитываются при сертификации Tier, однако, по словам Гэри Вонга (Gary Wong) из телекоммуникационной компании Instor Solutions, метод сейсмической изоляции учитывается Uptime Insitute для присуждения Tier IV в сейсмически опасных районах. Что касается обновления статуса дата-центров Fujitsu в Австралии, оно было вызвано отключением из-за удара молнии в 2015 году, рассказал исполнительный директор Fujitsu в Австралии и Новой Зеландии Майк Фостер (Mike Foster).

На практике получается, что возможностей дата-центров Tier I и Tier II обычно достаточно для предприятий, которые могут справиться со случайным простоем сервера в нерабочее время. Для компаний, чей бизнес функционирует в режиме 24 часа в сутки по всему миру, или для компаний, где любой простой отрицательно скажется на операционной деятельности, инвестиции в Tier III или Tier IV могут себя оправдать.

Иначе говоря, Tier I подойдет для малых предприятий, в которых IT-инфраструктура лишь расширяет внутренние бизнес-процессы и не является основным инструментом. Tier II будет достаточным для малых предприятий, чьи IT-запросы в основном ограничены традиционными рабочими часами и позволяют отключать систему в нерабочее время. Крупные предприятия с обязательствами по круглосуточному обслуживанию клиентов и автоматизации бизнес-процессов, работающие в сферах, где качество сервиса является конкурентным преимуществом, могут выбирать между Tier III и Tier IV. При этом защита от простоев в случае с Tier III является достаточной в большинстве ситуаций.

Например, мы в «ИТ-ГРАД» выбрали для размещения части своей распределенной инфраструктуры ЦОД SDN, который является дата-центром уровня Tier III. Этого достаточно, чтобы предоставлять востребованные IT-услуги, начиная от co-location и заканчивая арендой IaaS-облака, сертифицированного в соответствии с требованиями стандарта PCI DSS.

Для обеспечения должной надежности в SDN используются такие решения, как динамические источники бесперебойного питания, собственная распределительная подстанция, модульная структура, охлаждение силами установки KyotoCooling B.V. на основе роторного теплообмена. Безопасность дата-центра обеспечивается многоуровневой защитой с несколькими периметрами.


Поддержка температурно-влажностного режима в SDN

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

P.S. Еще несколько материалов по теме из Первого блога о корпоративном IaaS:

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332864/


Метки:  

Smart IDReader SDK — добавляем распознавание в Android приложения

Вторник, 18 Июля 2017 г. 09:01 + в цитатник

Привет, Хабр! В одной из прошлых наших статей изучался вопрос встраивания ядра распознавания Smart IDReader в iOS приложения. Пришло время обсудить эту же проблему, но для ОС Android. Ввиду большого количества версий системы и широкого парка устройств это будет посложнее, чем для iOS, но всё же вполне решаемая задача. Disclaimer – приведённая ниже информация не является истинной в последней инстанции, если вы знаете как упростить процесс встраивания/работы с камерой или сделать по другому – добро пожаловать в комментарии!


Допустим, мы хотим добавить функционал распознавания документов в своё приложение и для этого у нас есть Smart IDReader SDK, который состоит из следующих частей:


  • bin – сборка библиотеки ядра libjniSmartIdEngine.so для 32х битной архитектуры ARMv7
  • bin-64 – сборка библиотеки ядра libjniSmartIdEngine.so для 64х битной архитектуры ARMv8
  • bin-x86 – сборка библиотеки ядра libjniSmartIdEngine.so для 32х битной архитектуры x86
  • bindings – JNI обёртка jniSmartIdEngineJar.jar над библиотекой libjniSmartIdEngine.so
  • data – файлы конфигурации ядра
  • doc – документация к SDK

Некоторые комментарии по содержанию SDK.


Наличие трех сборок библиотеки под разные платформы – плата за большое разнообразие устройств на ОС Android (сборку для MIPS не делаем по причине отсутствия устройств данной архитектуры). Сборки для ARMv7 и ARMv8 являются основными, версия для x86 обычно используется нашими клиентами для конкретных устройств на базе мобильных процессоров Intel.


Обёртка JNI (Java Native Interface) jniSmartIdEngineJar.jar требуется для вызова C++ кода из Java приложений. Сборка обёртки у нас автоматизирована с помощью инструментария SWIG (simplified wrapper and interface generator).


Итак, как говорят французы, revenons `a nos moutons! У нас есть SDK и нужно с минимальными усилиями встроить его в проект и начать использовать. Для этого потребуются следующие шаги:


  1. Добавление необходимых файлов к проекту
  2. Подготовка данных и инициализация движка
  3. Подключение камеры к приложению
  4. Передача данных и получение результата

Для того чтобы каждый мог поиграться с библиотекой мы подготовили и выложили исходный код Smart IDReader Demo for Android на Github. Проект сделан для Android Studio и демонстрирует пример работы с камерой и ядром на основе простого приложения.


Добавление необходимых файлов к проекту


Рассмотрим данный процесс на примере проекта приложения под Android Studio, для пользователей других IDE процесс не особо отличается. По умолчанию в каждом проекте Android Studio создает папку libs, из которой сборщик Gradle забирает и добавляется к проекту JAR файлы. Именно туда скопируем JNI обёртку jniSmartIdEngineJar.jar. Для добавления библиотек ядра существует несколько способов, проще всего это сделать с помощью JAR архива. Создаем в папке libs архив с именем native-libs.jar (это важно!) и внутри архива подпапки lib/armeabi-v7a и lib/arm64-v8a и помещаем туда соответствующие версии библиотек (для x86 библиотеки подпапка будет lib/x86).


В этом случае ОС Android после установки приложения автоматически развернёт нужную версию библиотеки для данного устройства. Сопутствующие файлы конфигурации движка добавляем в папку assets проекта, если данная папка отсутствует, то её можно создать вручную или с помощью команды File|New|Folder|Assets Folder. Как видим, добавить файлы к проекту очень просто и занимает совсем немного времени.


Подготовка данных и инициализация движка


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


  • Развернуть файлы конфигурации ядра из assets
  • Загрузить библиотеку и инициализировать движок

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


// текущая версия кода приложения
int version_code = BuildConfig.VERSION_CODE;

SharedPreferences sPref = PreferenceManager.getDefaultSharedPreferences(this);

// версия кода из настроек
int version_current = sPref.getInt("version_code", -1);

// если версии отличаются нужно обновить данные
need_copy_assets = version_code != version_current;

// обновляем версию кода в настройках
SharedPreferences.Editor ed = sPref.edit();
ed.putInt("version_code", version_code);
ed.commit();

…
if (need_copy_assets == true)
    copyAssets();

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


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


private static RecognitionEngine engine;
private static SessionSettings sessionSettings;
private static RecognitionSession session;
...
сlass InitCore extends AsyncTask {

    @Override
    protected Void doInBackground(Void... unused) {

        if (need_copy_assets)
            copyAssets();

        // конфигурирование ядра
        configureEngine();
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);

        if(is_configured)
        {
            // устанавливаем ограничения на распознаваемые документы (например, rus.passport.* означает подмножество документов российского паспорта)
            sessionSettings.AddEnabledDocumentTypes(document_mask);

            // получаем полные наименования распознаваемых документов
            StringVector document_types = sessionSettings.GetEnabledDocumentTypes();
            ...
        }
    }
}
…
private void configureEngine() {

    try {
        // загрузка библиотеки ядра
        System.loadLibrary("jniSmartIdEngine");

        // путь к файлу настроек ядра
        String bundle_path = getFilesDir().getAbsolutePath() + File.separator + bundle_name;

        // инициализация ядра
        engine = new RecognitionEngine(bundle_path);
        // инициализация настроек сессии
        sessionSettings = engine.CreateSessionSettings();

        is_configured = true;

    } catch (RuntimeException e) {
        ...

    }
      catch(UnsatisfiedLinkError e) {
        ...
      }
}

Подключение камеры к приложению


Если ваше приложение уже использует камеру, то можете спокойно пропустить этот раздел и перейти к следующему. Для оставшихся рассмотрим вопрос использования камеры для работы с видео потоком для распознавания документов посредством Smart IDReader. Сразу оговоримся, что мы используем класс Camera, а не Camera2, хотя он и объявлен как deprecated начиная с версии API 21 (Android 5.0). Это осознанно сделано по следующим причинам:


  • Класс Camera значительно проще в использовании и содержит необходимый функционал
  • Поддержка старых устройств на Android 2.3.x и 4.x.x до сих пор актуальна
  • Класс Camera до сих пор отлично поддерживается, тогда как в начале запуска Android 5.0 у многих производителей были проблемы с реализацией Camera2

Чтобы добавить поддержку камеры в приложение нужно прописать в манифест следующие строки:




Хорошим тоном является запрос разрешения на использование камеры, реализованные в Android 6.x и выше. К тому же пользователи этих систем всегда могут отобрать разрешения у приложения в настройках, так что проверку все равно проводить нужно.


// если необходимо - запрашиваем разрешение
if( needPermission(Manifest.permission.CAMERA) == true )
    requestPermission(Manifest.permission.CAMERA, REQUEST_CAMERA);  
…
public boolean needPermission(String permission) {
    // проверка разрешения
    int result = ContextCompat.checkSelfPermission(this, permission);
    return result != PackageManager.PERMISSION_GRANTED;
}

public void requestPermission(String permission, int request_code)
{
    // запрос на разрешение работы с камерой
    ActivityCompat.requestPermissions(this, new String[]{permission}, request_code);
}

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults)
{
    switch (requestCode) {
        case REQUEST_CAMERA: {
            // запрос на разрешение работы с камерой
            boolean is_granted = false;
            for(int grantResult : grantResults)
            {
                if(grantResult == PackageManager.PERMISSION_GRANTED)  // разрешение получено
                    is_granted = true;
            }
                if (is_granted == true)
               {
                    camera = Camera.open();  // открываем камеру
                    ....
               }
              else
                  toast("Enable CAMERA permission in Settings");
        }
        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

Важной частью работы с камерой является установка её параметров, а именно режима фокусировки и разрешения предпросмотра. Из-за большого разнообразия устройств и характеристик их камер этому вопросу следует уделить особое внимание. Если камера не поддерживает возможности фокусировки, то приходится работать с фиксированным фокусом или направленным на бесконечность. В таком случае особо ничего сделать нельзя, получаем изображения с камеры as is. А если нам повезло и фокусировка доступна, то проверяем, поддерживаются ли режимы FOCUS_MODE_CONTINUOUS_PICTURE или FOCUS_MODE_CONTINUOUS_VIDEO, что означает постоянный процесс фокусировки на объектах съемки в процессе работы. Если эти режимы поддерживаются, то выставляем их в параметрах. Если же нет, то можно сделать следующий финт – запустить таймер и самим вызывать функцию фокусировки у камеры с заданной периодичностью.


Camera.Parameters params = camera.getParameters();

// список поддерживаемых режимов фокусировки
List focus_modes = params.getSupportedFocusModes();
String focus_mode = Camera.Parameters.FOCUS_MODE_AUTO;
boolean isAutoFocus = focus_modes.contains(focus_mode);

if (isAutoFocus) {
    if (focus_modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE))
        focus_mode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE;
    else if (focus_modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO))
        focus_mode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO;
} else {
    // если нет автофокуса то берём первый возможный режим фокусировки
    focus_mode = focus_modes.get(0);
}

// установка режима фокусировки
params.setFocusMode(focus_mode);

// запуск автофокуса по таймеру если нет постоянного режима фокусировки
if (focus_mode == Camera.Parameters.FOCUS_MODE_AUTO)
{
    timer = new Timer();
    timer.schedule(new Focus(), timer_delay, timer_period);
}
…
// таймер периодической фокусировки
private class Focus extends TimerTask {

    public void run() {
        focusing();
    }
}

public void focusing() {

    try{
        Camera.Parameters cparams = camera.getParameters();

        // если поддерживается хотя бы одна зона для фокусировки 
        if( cparams.getMaxNumFocusAreas() > 0)
        {
            camera.cancelAutoFocus();
            cparams.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
            camera.setParameters(cparams);
        }
    }catch(RuntimeException e)
    {
        ...
    }
}

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


DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);

// соотношение сторон экрана
float best_ratio = (float)metrics.heightPixels / (float)metrics.widthPixels;

List sizes = params.getSupportedPreviewSizes();
Camera.Size preview_size = sizes.get(0);

 // допустимое отклонение от оптимального соотношения при выборе
final float tolerance = 0.1f;
float preview_ratio_diff = Math.abs( (float) preview_size.width / (float) preview_size.height - best_ratio);

// выбираем оптимальное разрешение preview камеры по соотношению сторон экрана
for (int i = 1; i < sizes.size() ; i++)
{
    Camera.Size tmp_size = sizes.get(i);
    float tmp_ratio_diff =  Math.abs( (float) tmp_size.width / (float) tmp_size.height - best_ratio);

    if( Math.abs(tmp_ratio_diff - preview_ratio_diff) < tolerance && tmp_size.width > preview_size.width || tmp_ratio_diff < preview_ratio_diff)
    {
        preview_size = tmp_size;
        preview_ratio_diff = tmp_ratio_diff;
    }
}

// установка размера preview в настройках камеры
params.setPreviewSize(preview_size.width, preview_size.height);

Осталось совсем немного – установить ориентацию камеры и отображение preview на поверхность Activity. По умолчанию углу 0 градусов соответствует альбомная ориентация устройства, при поворотах экрана её нужно соответственно менять. Тут можно еще вспомнить добрым словом Nexus 5X от Google, матрица которого установлена в устройстве вверх ногами и для которого нужна отдельная проверка на ориентацию.


private boolean is_nexus_5x = Build.MODEL.contains("Nexus 5X");
SurfaceView surface = (SurfaceView) findViewById(R.id.preview);
...
// портретная ориентация
camera.setDisplayOrientation(!is_nexus_5x ? 90: 270);
// отображение preview на поверхность приложения
camera.setPreviewDisplay(surface.getHolder());
// начало процесса preview
camera.startPreview();

Передача данных и получение результата


Итак, камера подключена и работает, осталось самое интересное – задействовать ядро и получить результат. Запускаем процесс распознавания, начав новую сессию и установив callback для получения кадров с камеры в режиме preview.


void start_session()
{
    if (is_configured == true && camera_ready == true) {

        // установка параметров сессии, например тайм-аут
        sessionSettings.SetOption("common.sessionTimeout", "5.0");

        // создании сессии распознавания
        session = engine.SpawnSession(sessionSettings);

        try {

            session_working = true;

            // семафоры готовности кадра к обработке и ожидания кадра
            frame_waiting = new Semaphore(1, true);
            frame_ready = new Semaphore(0, true);

            // запуск потока распознавания в отдельном AsyncTask
            new EngineTask().execute();

        } catch (RuntimeException e) {
            ...
        }

        // установка callback для получения изображений с камеры
        camera.setPreviewCallback(this);
    }
}

Функция onPreviewFrame() получает текущее изображение с камеры в виде массива байт формата YUV NV21. Так как она может вызываться только в основном потоке, чтобы его не замедлять вызовы ядра для обработки изображения помещаются в отдельный поток с помощью AsyncTask, синхронизация процесса происходит с помощью семафоров. После получения изображения с камеры даём сигнал рабочему потоку начать его обработку, по окончании — сигнал на получение нового изображения.


// текущее изображение
private static volatile byte[] data;
 ...
@Override
public void onPreviewFrame(byte[] data_, Camera camera)
{
    if(frame_waiting.tryAcquire() && session_working)
    {
        data = data_;
        // семафор готовности изображения к обработке
        frame_ready.release();
    }
}
…
class EngineTask extends AsyncTask
{
    @Override
    protected Void doInBackground(Void... unused) {

        while (true) {

            try {
                frame_ready.acquire();  // ждем новый кадр

                if(session_working == false) // остановка если сессия завершена
                    break;

                Camera.Size size = camera.getParameters().getPreviewSize();
                // передаём кадр в ядро и получаем результат
                RecognitionResult result = session.ProcessYUVSnapshot(data, size.width, size.height, !is_nexus_5x ? ImageOrientation.Portrait : ImageOrientation.InvertedPortrait);
                ...
                // семафор ожидания нового кадра
                frame_waiting.release();
            }catch(RuntimeException e)
            {
                ...            }
            catch(InterruptedException e)
            {
                ...
            }
        }
        return null;
    }

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


void show_result(RecognitionResult result)
{
    // получаем распознанные поля с документа
    StringVector texts = result.GetStringFieldNames();
    // получаем изображения с документа, такие как фотография, подпись и так далее
    StringVector images = result.GetImageFieldNames();

    for (int i = 0; i < texts.size(); i++)   // текстовые поля документа
    {
        StringField field = result.GetStringField(texts.get(i));
        String value = field.GetUtf8Value();  // данные поля
        boolean is_accepted = field.IsAccepted();  .. статус поля
        ...
    }

    for (int i = 0; i < images.size(); i++)  // графические поля документа
    {
        ImageField field = result.GetImageField(images.get(i));
        Bitmap image = getBitmap(field.GetValue());  // получаем Bitmap
        ...
    }

    ...
}

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


void stop_session()
{
    session_working = false;
    data = null;

    frame_waiting.release();
    frame_ready.release();

    camera.setPreviewCallback(null);  // останавливаем процесс получения изображений с камеры
    ...
}

Заключение


Как можно убедиться на нашем примере, процесс подключения Smart IDReader SDK к Android приложениям и работа с камерой не являются чем-то сложным, достаточно всего лишь следовать некоторым правилам. Целый ряд наших заказчиков успешно применяют наши технологии в своих мобильных приложениях, причем сам процесс добавления нового функционала занимает весьма небольшой время. Надеемся, с помощью данной статьи и вы смогли убедиться в этом!


P.S. Чтобы посмотреть, как Smart IDReader выглядит в нашем исполнении после встраивания, вы можете скачать бесплатные полные версии приложений из App Store и Google Play.

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332670/


[Перевод] Непрерывная интеграция: CircleCI vs Travis CI vs Jenkins

Вторник, 18 Июля 2017 г. 09:00 + в цитатник


Под катом вы найдете перевод статьи ознакомительного характера, в которой сравниваются три системы непрерывной интеграции: CircleCI, Travis CI и Jenkins.


Определение и назначение CI


Непрерывная интеграция (CI, Continuous Integration) — это практика разработки программного обеспечения, при которой изменения кода с высокой частотой интегрируются в общий репозиторий и проверяются с помощью автоматической сборки.


Непрерывная интеграция нацелена на ускорение и облегчение процесса выявления проблем, возникающих в процессе разработки программного обеспечения. При регулярной интеграции изменений единовременный объем проверок уменьшается. В результате на отладку тратится меньше времени, которое можно перераспределить на добавление новых функций. Также возможно добавить проверку стиля кода, цикломатической сложности (чем ниже сложность, тем легче тестировать) и другие виды контроля. Это упрощает рецензирование кода (code review), экономит время и улучшает качество кода.


Как это работает




  • Разработчики проверяют код локально на своих компьютерах.
  • Затем изменения отправляются в общий репозиторий.
  • Репозиторий отправляет запрос (webhook) системе CI.
  • CI-сервер запускает задание (тесты, покрытие, проверку синтаксиса и т. д.).
  • CI-сервер сохраняет артефакты и выпускает релиз для тестирования.
  • В случае возникновения ошибок сборки или тестирования CI-сервер оповещает команду.
  • Команда исправляет проблему.

CircleCI vs Travis CI vs Jenkins


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


CircleCI




Функции:


  • CircleCI — это облачная система, для которой не нужно настраивать отдельный сервер и которую не придется администрировать. Однако существует и локальная версия, которую вы можете развернуть в частном облаке.
  • Даже для коммерческого использования существует бесплатная версия.
  • С помощью REST API можно получить доступ к проектам, сборкам и артефактам. Результатом сборки является артефакт или группа артефактов. Артефактом могут быть скомпилированное приложение или исполняемые файлы (например, APK для Android) или метаданные (например, информация об удачно завершившемся тестировании).
  • CircleCI кэширует сторонние зависимости, что позволяет избежать постоянной установки необходимых окружений.
  • Существует возможность подключения к контейнеру по SSH. Это может потребоваться, если возникнут какие-то проблемы.
  • CircleCI — полностью готовое решение, требующее минимальной настройки.

CircleCI совместима с:


  • Python, Node.js, Ruby, Java, Go и т. д.;
  • Ubuntu (12.04, 14.04), Mac OS X (платные аккаунты);
  • Github, Bitbucket;
  • AWS, Azure, Heroku, Docker, выделенный сервер;
  • Jira, HipChat, Slack.

Достоинства CircleCI:


  • легкое и быстрое начало работы;
  • бесплатная версия для коммерческого использования;
  • небольшие и легко читаемые файлы конфигурации в формате YAML;
  • отсутствие необходимости в выделенном сервере CircleCI.

Недостатки CircleCI:


  • CircleCI в бесплатной версии поддерживает только Ubuntu 12.04 и 14.04. Для использования MacOS придется заплатить;
  • несмотря на то что CircleCI может работать с любыми языками программирования, из коробки поддерживаются только Go (Golang), Haskell, Java, PHP, Python, Ruby/Rails, Scala;
  • при желании подстроить систему под себя в некоторых случаях могут возникнуть проблемы, и тогда для достижения цели понадобится стороннее программное обеспечение.

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


Travis CI




Travis CI и CircleCI очень похожи


Обе системы:


  • используют файлы конфигурации в формате YAML;
  • развернуты в облаке;
  • поддерживают Docker для запуска тестов.

Что есть в TravisCI и нет в CircleCI?


  • Запуск тестов одновременно под Linux и Mac OS X.
  • Поддержка большего количества языков «из коробки»:
    Android, C, C#, C++, Clojure, Crystal, D, Dart, Erlang, Elixir, F#, Go, Groovy, Haskell, Haxe, Java, JavaScript (with Node.js), Julia, Objective-C, Perl, Perl6, PHP, Python, R, Ruby, Rust, Scala, Smalltalk, Visual Basic.
  • Поддержка build matrix.

Build matrix


language: python  
python:  
  - "2.7"
  - "3.4"
  - "3.5"
env:  
  - DJANGO='django>=1.8,<1.9'
  - DJANGO='django>=1.9,<1.10'
  - DJANGO='django>=1.10,<1.11'
  - DJANGO='https://github.com/django/django/archive/master.tar.gz'
matrix:  
  allow_failures:
    - env: DJANGO='https://github.com/django/django/archive/master.tar.gz'

Build matrix — это инструмент, который дает возможность выполнять тесты, используя разные версии языков и пакетов. Он обладает богатыми возможностями по настройке. Например, при неудачных сборках в некоторых окружениях система может выдать предупреждение, но сборка целиком не будет считаться неудачной (это удобно при использовании dev-версий пакетов).


TOX


Если вы предпочитаете какую-либо другую CI-платформу, то Build Matrix можно создать с помощью Tox.


[tox]
envlist = py{27,34,35}-django{18,19,110,master}

[testenv]
deps =  
    py{27,34,35}: -rrequirements/test.txt
    django18: Django>=1.8,<1.9
    django19: Django>=1.9,<1.10
    django110: Django>=1.10,<1.11
    djangomaster: https://github.com/django/django/archive/master.tar.gz
commands = ./runtests.py

[testenv:py27-djangomaster]
ignore_outcome = True

Tox — это универсальный консольный инструмент по управлению пакетами и их тестированию в virtualenv. Его можно установить с помощью pip install tox или easy_install tox.


Достоинства Travis CI:


  • build matrix «из коробки»;
  • быстрый старт;
  • небольшие и легко читаемые файлы конфигурации в формате YAML;
  • бесплатная версия для opensource-проектов;
  • отсутствие необходимости в выделенном сервере.

Недостатки Travis CI:


  • по сравнению с CircleCI цены выше, нет бесплатной версии для коммерческого использования;
  • ограниченные возможности по настройке (для некоторых вещей может потребоваться сторонний софт).

Jenkins




Возможности:


  • Jenkins — это автономное приложение на Java, которое может работать под Windows, Mac OS X и другими unix-подобными операционными системами.
  • В Update Center можно найти сотни плагинов, поэтому Jenkins интегрируется практически с любым инструментом, относящимся к непрерывной интеграции и непрерывной поставке (continuous delivery).
  • Возможности Jenkins могут быть практически неограниченно расширены благодаря системе подключения плагинов.
  • Предусмотрены различные режимы: Freestyle project, Pipeline, External Job, Multi-configuration project, Folder, GitHub Organization, Multibranch Pipeline.
  • Jenkins Pipeline — это набор плагинов, поддерживающих создание и интеграцию в Jenkins цепочек непрерывной поставки. Pipeline предоставляет расширяемый набор инструментов по моделированию цепочек поставки типа "as code" различной степени сложности с помощью Pipeline DSL.
  • Позволяет запускать сборки с различными условиями.
  • Jenkins может работать с Libvirt, Kubernetes, Docker и др.
  • Используя REST API, можно контролировать количество получаемых данных, получать/обновлять config.xml, удалять задания (job), получать все сборки, получать/обновлять описание задания, выполнять сборку, включать/отключать задания.

Достоинства Jenkins:


  • цена (он бесплатен);
  • возможности по настройке;
  • система плагинов;
  • полный контроль над системой.

Недостатки Jenkins:


  • требуется выделенный сервер (или несколько серверов), что влечет за собой дополнительные расходы на сам сервер, DevOps и т. д.;
  • на настройку необходимо время.

Заключение


Какую систему CI выбрать? Это зависит от ваших потребностей и планируемого способа использования этого инструмента.


CircleCI хорошо подходит для небольших проектов, где основная задача — запустить непрерывную интеграцию как можно быстрее.


Travis CI рекомендуется в первую очередь для open-source проектов, которые необходимо тестировать в различных окружениях.


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


Ссылки:


  1. Оригинал: Continuous Integration. CircleCI vs Travis CI vs Jenkins.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332836/


Метки:  

Расширяем экосистему Skyeng, открыв API словаря — первые участники конкурса

Вторник, 18 Июля 2017 г. 08:58 + в цитатник

Месяц назад мы открыли API нашего словаря, предложили всем желающим использовать его в своих приложениях и сервисах и даже объявили конкурс среди разработчиков. За прошедшее время мы получили 18 конкурсных заявок, среди них несколько готовых решений. Сегодня мы решили в своем блоге дать авторам четырех из них возможность рассказать о своем продукте (а мы прокомментируем).


Если вы пропустили пост о нашей экосистеме, где был объявлен конкурс – вот ссылка. На тот момент у нас еще не были готовы условия конкурса — вот и они. Призовой фонд нашего конкурса составляет 200 тысяч рублей — деньги для разработчика нового приложения или сервиса не бывают лишними!


Ну а теперь — к знакомству с первыми участниками.


Евгений Криулин – Lenny English Bot


Lenny — это чатбот, который помогает пользователям пополнять их словарный запас по 10 слов в день. ЦА — это люди, которые изучают английский прямо сейчас или изучали его ранее. Большой словарный запас нужен для того, чтобы хорошо говорить, легко читать, понимать других и просто думать.


Чтобы слова не забывались, их нужно регулярно «освежать» в памяти. Далеко ходить мы не стали и построили алгоритм повторения на основе кривой забывания Эббингауза. На деле это значит, что пользователь повторяет слова через 30 минут, 1 день, 1 неделю, 1 месяц и 1 год. Таким образом слова закрепляются долговременной памяти. А в нужный момент их можно оттуда достать и применить.


Теперь о контенте. Перед началом конкурса у нас уже была база из 10 000 слов. И когда Skyeng предоставляет возможность сделать базу еще лучше, ей надо пользоваться. Мы так и сделали, получив и сохранив в отдельные файлы все необходимое.


А именно:


Примеры использования
import requests
import time

from content import dictionary

def skyeng_word(word):
    url = "http://dictionary.skyeng.ru/api/public/v1/words/search?_format=json&search={}".format(word)
    response = requests.get(url)
    try:
        ids = response.json()[0]['meanings'][0]['id']
        return skyeng_meaning(ids)
    except:
        return None

def skyeng_meaning(ids):
    url = "http://dictionary.skyeng.ru/api/public/v1/meanings?_format=json&ids={}".format(ids)
    response = requests.get(url)
    return response.json()[0]['examples'][0]['text']

def get_example(word):
    example = skyeng_word(word)

    if example is not None:
        return example
    else:
        return '!!! {} !!!'.format(word)

def add_example():
    i = 1
    while i <= 10000:
        time.sleep(1)
        example = get_example(dictionary[i]['word'])

        with open('examples.py', 'a') as file:
            file.write("{}: \"{}\"\n".format(i, example))

        print(i)
        i += 1

if __name__ == '__main__':
    add_example()

Определения
import requests
import time

from content import dictionary

def skyeng_word(word):
    url = "http://dictionary.skyeng.ru/api/public/v1/words/search?_format=json&search={}".format(word)
    response = requests.get(url)
    try:
        ids = response.json()[0]['meanings'][0]['id']
        return skyeng_meaning(ids)
    except:
        return None

def skyeng_meaning(ids):
    url = "http://dictionary.skyeng.ru/api/public/v1/meanings?_format=json&ids={}".format(ids)
    response = requests.get(url)
    return response.json()[0]['definition']['text']

def get_definition(word):
    definition = skyeng_word(word)

    if definition is not None:
        return definition
    else:
        return '!!! {} !!!'.format(word)

def add_definition():
    i = 1
    while i <= 10000:
        time.sleep(1)
        definition = get_definition(dictionary[i]['word'])

        with open('definitions.py', 'a') as file:
            file.write("{}: \"{}\"\n".format(i, definition))

        print(i)
        i += 1

if __name__ == '__main__':
    add_definition()

И произношения слов
import requests
import time

from content import dictionary

def skyeng_word(word):
    url = "http://dictionary.skyeng.ru/api/public/v1/words/search?_format=json&search={}".format(word)
    response = requests.get(url)
    try:
        voice_url = "http:{}".format(response.json()[0]['meanings'][0]['soundUrl'])
        return requests.get(voice_url)
    except:
        return None

def get_voice():
    i = 1
    while i <= 10000:
        time.sleep(1)
        voice = skyeng_word(dictionary[i]['word'])
        file_name = '{}.ogg'.format(i)

        if voice is not None:
            with open(file_name, 'wb') as file:
                file.write(bytes(voice.content))

        print(i)
        i += 1

if __name__ == '__main__':
    get_voice()

Далее мы просто обновили текущую базу всем сохраненным.


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


Закончить свой дебют на Хабре хотелось бы афоризмом. Он отражает философию нашей небольшой команды — «Words can inspire and words can destroy. They are important to learn».


Благодарим школу Skyeng за возможность сделать продукт лучше. Спасибо всем, удачи!


Skyeng: Нам очень нравится бот LennyEnglishBot, он минималистичный и ненавязчивый, а работает на трех платформах – Telegram, Facebook и Viber. Для тех, кто не хочет или не может ставить лишнее приложение в телефон – самое оно, порог вхождения минимальный. В нашей экосистеме такой продукт очень был нужен.


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


Наиль Галиаскаров — readore.io


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



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


С помощью API SkyEng наше приложение теперь снова будет работать в Украине (до этого мы использовали Яндекс.Словарь), я как раз искал бесплатную альтернативу. Ну и теперь по многочисленным просьбам пользователей, readore может похвастаться offline-словарем.


Skyeng: Нам это приложение понравилось. Симпатичное, похоже на Bookmate. В некоторых книжках есть встроенная озвучка. Встроен словарь и переводчик, можно отмечать слова на изучение. И самое приятное, что в ближайшее время у учеников нашей школы появится возможность добавлять слова на изучение в нашем мобильном приложении Words.


Дмитрий Садовников — Enwords


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



Прочитал когда-то статью на geektimes, из которой узнал про сайт tatoeba.org. Выгрузил оттуда список предложений, распарсил и выбрал самые часто встречающиеся слова, а дальше решил не ограничиваться только английским языком. В итоге была создана своя база, состоящая из 3.5 миллионов предложений, 500 тысяч слов на 30 языках, включая даже эсперанто. Создал web-приложение, в котором можно добавлять слова для изучения и отмечать выученные. Запоминание слов происходит при повторении их в небольших фразах.


Есть режим тренировок, где фразу нужно полностью перепечатать (заодно можно тренировать слепую печать). Можно загрузить текст для изучения, обычно использую тексты из уроков A.J. Hoge, он парсится, на выходе получается список слов, отсортированный по частоте встречаемости в этом тексте. Приложение не подойдет совсем новичкам в иностранных языках, грамматических уроков здесь нет.


Недавно подключил Skyeng API в связке с jQuery плагином qtip, теперь по клику на английское слово отправляется ajax запрос в Skyeng, и появляется перевод слова с озвучкой. Я давно хотел подключить такой функционал, руки не доходили, но со Skyeng это заняло буквально час. В ближайшее время позволю своим пользователям изучать слова, которые они добавили в учетной записи Skyeng, надеюсь это повысит конверсию.


Проект opensource, полностью бесплатный, если будет много пользователей, придется вводить платные функции, сервера нужно оплачивать, но основа все равно будет доступна для всех.
Написан на Ruby on Rails, любой желающий может предлагать свои идеи по функционалу, дизайну, маркетингу, вообще от product manager’а я бы не отказался.


Код проекта


Skyeng: Enwords предоставляет возможность самостоятельно составлять списки слов для изучения, это функционал, который активно просят пользователи нашего приложения Words. Однако текстовый парсер, в отличие от нашего Wordset Generator, не умеет сортировать слова по уровню сложности, поэтому на выходе получается очень большой список, начинающийся с артиклей, местоимений и заведомо всем известных слов; таким образом, надо потратить время на извлечение нужной для изучения лексики. Важная фишка Enwords – открытый исходный код.


UPD: новая важная фишка — возможность добавлять слова из своего аккаунта в Skyeng, достаточно указать e-mail в поле "Настройки Skyeng". Отлично!


Дмитрий Лапаев – Больше Слов


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


API Skyeng в настоящий момент используется в виде реализации запроса (метод "search": dictionary.skyeng.ru/api/public/v1/words/search). Порадовало то, что работает без авторизации, а результаты предоставляются как для русских, так и английских слов. Из структуры результатов запроса возникла простая реализация приложения в виде двух фрагментов: «список полученных (по запросу) слов» и «отображение значений (вариантов перевода)». Полученные значения отображаются в виде «визуальных карточек» с возможностью загрузки аудио-файлов для воспроизведения транскрипции. Результаты поискового запроса сохраняются в БД приложения (состоит из двух связанных таблиц, используется ORM Lite), аудио-файлы и изображения хранятся в директории приложения.


Каждому слову (результаты запроса) назначается одна из категорий:
1) "Для изучения",
2) "Изученное",
3) "Избранное",
4) "Просмотренное" (назначается при выборе слова для просмотра значений перевода);
при перемещении в "Изученное" формируется тестовое задание: выбрать верный из пяти предложенных вариантов перевода, случайная выборка из таблицы "значения" при совпадении поля "часть речи" (Part of speech).


Skyeng: «Больше Слов» — по сути упрощенный аналог нашего приложения Words. Хотя он не очень вписывается в нашу экосистему, мы рады его существованию: мы за разнообразие и возможность выбора.


Конкурс Skeyng продолжается, мы надеемся увидеть еще больше интересных разработок, использующих наш API. Если у вас есть идея или готовое приложение — заполните заявку.


Ну а если вы хотите разрабатывать приложения внутри Skyeng — у нас, как всегда, есть интересные вакансии.

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333524/


Метки:  

«Ультимативный» блокчейн-дайджест: полезные материалы на Хабре и другие источники по теме

Вторник, 18 Июля 2017 г. 08:31 + в цитатник
Вчера мы представили открытый фреймворк для разработки блокчейнов Exonum. Он позволит компаниям и правительственным организациям воплощать в жизнь безопасные блокчейн-решения.

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

/ изображение Ron Mader CC



Для начинающих




«C чем это едят»: что такое блокчейн

Компания BitFury принимает участие в развитии блокчейна с 2011 года. Здесь мы рассказываем об истории данной технологии, даем простое объяснение принципов работы и знакомим с основными составляющими. Этот материал стоит использовать в качестве отправной точки и рекомендовать к прочтению всем, кто хотел бы понять, что такое блокчейн.

Что такое эксклюзивные блокчейны

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

Объяснение блокчейна для веб-разработчиков

Хабражитель Ratix подготовил перевод материала «The Blockchain Explained to Web Developers, Part 1: The Theory» за авторством Франсуа Занинотто (Francois Zaninotto). Это очередная попытка разобраться в теме с помощью самостоятельного перевода первоисточника. В этой статье вы найдете базовое определение блокчейна, краткий рассказ о криптовалютах, майнинге, блоках и контрактах.

Кто нужен блокчейн-проектам, где их искать и сколько платят специалистам

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

Кладбище блокчейн-проектов

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




Для любителей




Как майнить с помощью бумаги и ручки

mark_ablov подготовил перевод занимательной заметки Кена Ширриффа (Ken Shirriff), которую тот написал еще в 2014 году. Этот материал будет интересен тем, кто хотел бы перейти от слов к практике и разобраться в сути технологии. Помимо времени на решение задачи Кен предполагает и свое энергопотребление, хотя затраты на бумагу и ручки он исключил из общего обоснования экономической эффективности процесса.

Как масштабировать биткойн-блокчейн

Здесь мы разбираемся с тем, как устранить самый большой недостаток биткойн-блокчейна. Из этой статьи вы узнаете о тех решениях, которые предлагает мировое сообщество, и о том, какое из них станет частью биткойн-сети. Для тех, кто уже успел немного погрузиться в тему: речь пойдет о Segregated Witness и Lightning Network.

Как работать с метаданными блокчейна

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

Как запустить надстройку над биткойн-блокчейном

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




«Алгоритмы консенсуса»: Подтверждение доли и доказательство работы

Распределенный и децентрализованный характер архитектуры блокчейна ставит перед сообществом задачу распределенного консенсуса. В этой статье мы начинаем со структуры блокчейн-сетей, говорим о консенсусе и «доказательстве работы». Помимо этого — приводим альтернативы для PoW. Этот материал мы рекомендуем «продвинутым пользователям».

«Криптография в блокчейнах»: о хеш-функциях и цифровых подписях

Разбираемся с тем, что лежит в основе блокчейна. Здесь вы сможете узнать, что дает защиту от коллизий, познакомиться с «эффектом лавины» и найти «живые» примеры, которые наглядно иллюстрируют рассматриваемые понятия. В этом нам помогли Алиса и Боб, активные пользователи биткойна.

Различия, плюсы и минусы: публичные и приватные блокчейны

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

Обзор децентрализованных технологий. Часть 1 и Часть 2

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

Погружение в блокчейн: Быстрые и безопасные транзакции

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

200 строк на блокчейн

Лаури Хартикка (Lauri Hartikka) поможет разобраться с реализацией простейшего блокчейна на самописном примере, который он назвал NaiveChain. Сам проект написан на Javascript, а в материале Лаури рассказывает о его основных составляющих и архитектуре. Дополнительно для интересующихся: репозиторий на GitHub.



Кейсы




Как с помощью блокчейна защитить свои данные

Компания Acronis рассказывает в своем корпоративном блоге о том, каким образом новую технологию возможно применить в сфере обеспечения безопасности данных. Здесь кратко рассмотрена техническая сторона задачи и поставлены юридические вопросы, которые влияют на применение подобных решений на территории России.

Иное применение блокчейнов: Смарт-контракты

В одном их материалов блога Bitfury Group на Хабрахабре мы решили разобраться с тем, что из себя представляют смарт-контракты. Здесь мы кратко затронули примеры платформ для смарт-контрактов (Rootstock) и поговорили о будущем и практическом применении умных контрактов.

Разработки Университета ИТМО: Управление дронами на блокчейне

Университет ИТМО рассказывает об одном из точечных экспериментов своего сообщества. Сфера применения — управление беспилотниками. Платформа — Ethereum.

Блокчейн для управления городом: властям Дубая поможет IBM

Правительство Дубая планирует запустить управление инфраструктурой города на базе блокчейна уже в следующем году. Создаваемая платформа будет открытой и для других регионов. В своем корпоративном блоге на Хабре компания IBM (партнер проекта) подчеркивает, что возможности новой технологии должны и будут применяться не только в сфере финансовых услуг.

Регистрация прав на землю с помощью блокчейна

Bitfury Group поможет правительству Грузии вести регистрацию прав собственности на земельные участки с помощью технологии блокчейн. Об этом кейсе мы рассказывали в своем англоязычном блоге на Medium.

Электронное правительство на основе блокчейн-технологий

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

ТОП 10 ошибок при создании блокчейн-проектов от Gartner Inc

Владимир>Menaskop подготовил перевод материала, который предлагает взглянуть не только на технологическую, но и на управленческую составляющую блокчейн-проектов. Оригинал — в блоге Gartner на английском.

Блокчейн для ИИ

Трент МакКонахи (Trent McConaghy) поделился со своей аудиторией видением того, каким образом блокчейн может повлиять на развитие ИИ. Трент рассмотрел этот вопрос с точки зрения «стратегии голубого океана» и проанализировал возможности для работы с большими данными.

Для чего подойдет блокчейн

Блог Digital Chains на Medium представляет аудитории интересный англоязычный материал на тему практического применеия блокчейна. Здесь вы сможете найти 30 use-кейсов с примерами уже существующих проектов: от сервиса для доставки товаров и до методов управления медицинской историей пациентов.

Что может блокчейн

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

Где и как применять блокчейн

Майк Голдин (Mike Goldin), разработчик блокчейн-решений, записал тематический подкаст на тему возможностей новой технологии и проблем, которые приходится решать. Здесь вы сможете найти текстовый транскрипт выпуска.

17 use-кейсов для блончейна

Еще одна англоязычная подборка с огромным количеством примеров уже запущенных проектов (в среднем по 3-4 примера на каждый use-кейс). Данный материал подойдет тем, кто только начинает разбираться в теме.

27 отраслей для применения блокчейна

CB Insights, одна из наиболее авторитетных аналитических компаний, публикует свою подборку сфер применения блокчейна. Этот материал дополняет предыдущие новыми примерами реализованных проектов.

Другие тематические сборники:


Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332438/


Метки:  

QML: как легко получать футболки в конкурсах mail.ru по машинному обучению

Вторник, 18 Июля 2017 г. 03:44 + в цитатник

Метки:  

Нагрузочное тестирование Web-систем. Продолжаем подготовку

Понедельник, 17 Июля 2017 г. 19:48 + в цитатник
В статье описаны ряд моментов (количество соединений и последовательность выполнения, сторонние ресурсы в сценарии, группировка запросов), на которые стоит обращать внимание при подготовке к выполнению теста с высокой нагрузкой на Web-систему с Web-интерфейсом.
Предлагаю рассмотреть следующие элементы конфигурации сценария, которые могут повлиять на производительность вашего теста.

Хочу описать почему использование реальных методов HTTP важнее, чем его «быстрые» аналоги. Затронем необходимость использования проверок получаемых данных и выстраивание регулярных выражений для получения значений.

Получение ответов с реальным размером данных

По-моему, мнению как минимум в финальном тестировании Web-системы необходимо использовать те запросы, которые отправляет браузер. Если это был GET запрос, то мы должны симулировать только его и не подменять его например на HEAD. Основная разница между данными методами в том, что GET получает содержимое ответа, а HEAD нет. Казалось бы зачем мне получать не нужные данные например от картинок, css, шрифтов, но как показывает практика они не менее важны.

Сравним два типа запросов для одного и того же тестового ресурса
HEAD
image
GET
image

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

Например, наш Web-сервер настроен таким образом, что может обрабатывать только 100 одновременных подключений. В результате мы увидим, что первые 100 подключаться и будут работать как минимум 3 секунды. При этом все остальные 900 будут ждать возможности подключения. Как только кто-то из первой сотни закончит, то отдаст ресурсы следующему. То есть тысячный пользователь в нашем пример сможет начать работать с указанным запросом только примерно через 27 секунд. Если бы мы использовали HEAD метод, то тысячный пользователь получил бы доступ к системе уже через 2 секунды. (данные расчёты крайне грубые)

В результате мы видим, как использование «правильного» метода для обращения к серверу показывает реальную на него нагрузку.

Использованный на картинках является полностью синтетических для отображения большей наглядности по времени выполнения запросов. У вас может не быть столь больших запросов. Но даже при ответе в 100 — 200 Килобайт и использовании 5 000 пользователей мы можем наблюдать значительные замедления в работе Web-сервера.

Проверка получаемых данных

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

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

Сегодня, при интенсивном развитии технологий динамической работы с web-системами (AJAX, WebSocket, Flash, Java и др.), мы можем на один и тот же запрос получать различное содержимое. И необходимо быть уверенным, что текст ответа является правильным.

Построение «правильных» регулярных выражений

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

Я же хочу продемонстрировать почему надо их выстраивать правильно. Возьмем некую последовтельность запросов, которые при записи имели некие задержки.
image
На картинке задержки обозначены зелеными стрелками.
При выполнении сценария, утилита должна симулировать задержки между запросами тем самым гарантируя «реальную» нагрузку пользователя.

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

В результате мы видим, что общее время выполнения сценария уже немного отклонилось о того, как если бы это делал один пользователь. Если же учесть, что каждый виртуальный пользователь должен делать такую проверку, а у нас на одном компьютере запущено 1 000 таких, то время на их обработку увеличится в несколько раз. Каждый виртуальный пользователь будет захватывать ресурсы операционной системы для проведения вычислений. Следовательно, пока ресурсы заняты одними пользователями, другие не могут получить к ним доступ.

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

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

Заключение

Мы рассмотрели три возможных варианта, которые могут влиять на искажение результатов нагрузочного тестирования. Конечно не все из описанных ситуаций повлияют на такие параметры как время соединения с сервером, время ответа сервера и другие получаемые вами характеристики.
Но в большинстве случаев нас интересует сколько реальных пользователей выполняют тот или иной сценарий, с какой скоростью нам будет отвечать сервер, и какое время каждый из пользователей потратит на выполнение данного сценария. А вот на эти параметры могут поялиять расмотренные пункты.
Время ответа сервера на запрос у вас может составлять и несколько миллисекунд. При большем объеме получаемых данных и обработке их, время выполнения всего сценария может затянуться на несколько минут, что порой не приемлемо для заказчиков такого теста.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333504/


Метки:  

Бесплатные, линейные иконки для вашего сайта или приложения

Понедельник, 17 Июля 2017 г. 19:32 + в цитатник


Привет, Мир! На dribbble.com я нашел сет из 77 бесплатных иконок, которые мне очень понравились. Чтобы выразить свое спасибо автору, я запустил страницу на GitHub pages, для быстрого и удобного использования. Что именно получилось, читайте под катом.
Читать дальше ->

https://habrahabr.ru/post/333538/


Метки:  

[Из песочницы] Электронная демократия или как собрать и обработать данные по голосованию (и явке) за реновацию в Москве

Понедельник, 17 Июля 2017 г. 19:03 + в цитатник
Стоило голосованию за вход или выход из программы реновации завершиться — и с сайта мэра Москвы почему-то пропали данные о явке по каждому конкретному дому, остались только голоса за и против в целом. В новостях, конечно, пишут некие цифры, но ведь хочется посмотреть их самому, поиграться со статистикой, построить графики, не правда ли?

Да и после заявлений типа:
Что касается популярности этих сервисов, то центры госуслуг «Мои документы» привлекли чуть больше половины всех проголосовавших, незначительно уступив порталу «Активный гражданин»
как-то возникают лёгкие сомнения. Так что — приступим к сбору информации! А потом будем её анализировать. Для этого нам понадобится какой-нибудь язык (скажем, питон), какая-нибудь бд (скажем, sqlite) и какой-нибудь веб-скраппер, благо для питона их множество. Сразу говорю, в конце дам ссылку на получившуюся базу данных, можно сделать с ней что угодно.

Заходим на сайт мэрии, крутим колёсико. Надо собрать данные с 4543 домов. Кликам по случайному дому, по районным спискам, и смотрим, в каком формате вообще данные есть.

Судя по всему, у каждого дома есть некий id, который мы и видим в url:

https://www.mos.ru/otvet-stroitelstvo/itogi-golosovaniya-zhitelej-po-proektu-programmy-renovacii/?u=121

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

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

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

import requests
r = requests.get('https://www.mos.ru/otvet-stroitelstvo/itogi-golosovaniya-zhitelej-po-proektu-programmy-renovacii/?u=121')
print(r.text)

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



Ага! Мы обнаружили запрос браузера к некоему апи, причём айдишник совпадает с айдишником дома, который мы смотрим.

Иными словами, гет-запрос на www.mos.ru/altmosprx/api/1/renovation/house_result/121 безо всяких параметров даёт нам в ответ JSON такого вида:

{
  "execTime": 0.044450044631958,
  "errorMessage": "",
  "result": {
    "table": " ... 
Код квартирыИдентификатор голосаРешениеДатаВыбор квартиры
0G6O4

bf659227e8e3

5f9403659209

За

За

18.05

18.05

За

0G6O5

3f12be5cea77

За

15.05

За

0G6V1

5acd126a410ea1a842e67066ea68fa8f

За

24.05

За

", "total": { "und": 0, "za": 100, "protocol_res": 0, "protiv": 0, "gorod_mark": 0, "protocol_date": null, "house_status": 1, "gorod": 0 }, "und_table": "
Код квартирыИдентификатор голосаРешениеДатаВыбор квартиры
", "address": "Авиационная улица, дом 63, корпус 2" }, "request_id": "empty_requestid", "errorCode": 0 }

Отлично, тут нам даже не понадобится ничего скрапать, все данные и так есть сразу из апи. Всего-то нужно — посчитать количество apartment-id (всего голосов), взять готовые данные о проценте голосов за, об общедомовом собрании.

Но всё-таки, в каком диапазоне айдишников мы будем смотреть? Всего домов должно быть 4543. Даём апи 0 — есть такой дом. Даём -1 — ошибка, ну и на том спасибо. Нижнюю границу определили. Даём 10000 — есть такой дом. Ладно, их явно больше 4543. Попробуем определить верхнюю границу приблизительно, посмотрев какой-нибудь дом из недавно присоединённых территорий… Возвращаемся к карте, лезем куда-нибудь в «Новую Москву» подальше от «старой», о: поселение Кокошкино, дачный посёлок Кокошкино, улица Труда, дом 2, id: 440931. Ну, как минимум полмиллиона их у нас есть.

Перебирать полмиллиона ссылок в обычном loop'е — идея не самая лучшая, поэтому воспользуемся модулем concurrent.futures. Можно, конечно, было бы использовать что-нибудь вроде asyncio, но у нас не настолько масштабная задача и можно обойтись «малой кровью». Всё очень просто. Смотрим, что отдаёт апи при заведомо правильном номере дома, при заведомо неправильном, и делаем функцию для чекинга этого всего. Потом крутим это всё в цикле с паралелльными запросами, т.к. айдишников нужно обработать довольно много. Потом оформляем результат и записываем его. В целом получается примерно такой код:

import requests
from concurrent.futures import ProcessPoolExecutor
import concurrent.futures

def check(url):
    #try тут нужен, потому что гет-реквест, не смотря на таймаут, иногда плохо себя ведёт
    #мы же не хотим в конце перебора миллиона страничек получить краш с ошибкой
    try:
        r = requests.get('https://www.mos.ru/altmosprx/api/1/renovation/house_result/' + str(url) + '/', timeout=10)
        print(url)
        r.encoding = 'utf-8'
        if '400: Bad Request' not in r.text:
            return str(url)
    except:
    #ошибок будет немного, но лучше эти номера потом пробить ещё раз, для этого пишем и их
        woops = str(url) + ' failed'
        return woops
    
results = []
with ProcessPoolExecutor(max_workers=6) as executor:
    future_results = {executor.submit(check, url): url for url in range(0, 1000000)}
    #если нужны конкретные номера, то просто берём их из списка: url in somelist
    for future in concurrent.futures.as_completed(future_results):
        results.append(future.result())

results[:] = [item for item in results if item or item == 0]
#check возвращает None, если дома нет, убираем; а вот ноль нам нужен, не забудем о нём

with open('/home/deb/mosres.txt', 'w') as f:
    for item in results:
        f.write('{}\n'.format(item))

Запускаем и идём по своим делам — это надолго даже с 6 worker'ами. Забегая вперёд, скажу, что обработав миллион, получил где-то на 70 домов меньше, чем было в результатах, так что пришлось крутить эту волынку до 10 миллионов. Это долго, оставил работать и ушёл на работу.
Конечно, можно было бы поднять количество параллельных запросов, но мы же пользуемся чужим айпи, нужно вести себя вежливо (а то вдруг забанят).

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

Создадим бд. Все поля очевидны, разве что дом и дополнительные элементы типа корпуса, строения и т.п. разнесём — на всякий случай, если захотим, например, смотреть тенденции у рядом стоящих домов.

import sqlite3

schema = "CREATE TABLE `houses` (\
	`id`	INTEGER PRIMARY KEY,\
      `street` TEXT NOT NULL ,\
	`house_nbr`	TEXT NOT NULL,\
 	`house_additional`	TEXT,\
	`total_votes`	INTEGER,\
	`total_za`	INTEGER,\
	`meeting`	INTEGER DEFAULT '0',\
      `flats` INTEGER\
);"

conn = sqlite3.connect('renovation.db')
cur = conn.cursor()
db = cur.execute(schema)
conn.commit()
conn.close()

Ну что же, к делу! Сделаем функцию, достающую и добавляющую информацию по домам в базу, попутно будем записывать все JSON-ошибки (скорее всего, в ответе не было JSON) и неизвестные ошибки (скорее всего, ответа вообще не было), а потом можно будет их посмотреть и прогнать отдельно, если такие будут, конечно.

import requests
import re
import sqlite3

def gethouseinfo(idd):
    print(idd)
    urly = 'https://www.mos.ru/altmosprx/api/1/renovation/house_result/' + str(idd) + '/'
    try:
        r = requests.get(urly) 
        r.encoding = 'utf-8'
        results = r.json()
        adress = results['result']['address']
        print(adress)
        if re.match('(.*), (дом.*), (.*)', adress):
            adress_street = re.match('(.*), (дом.*), (.*)', adress).group(1)
            adress_house = re.match('(.*), (дом.*), (.*)', adress).group(2)
            adress_building = re.match('(.*), (дом.*), (.*)', adress).group(3)
        else:
            adress_street = re.match('(.*), (дом.*)', adress).group(1)
            adress_house = re.match('(.*), (дом.*)', adress).group(2)
            adress_building = ''
        totalvotes = len(re.findall('apartment-id', results['result']['table'])) + len(re.findall('apartment-id', results['result']['und_table']))
        aye = results['result']['total']['za']
        meetinghappened = bool(results['result']['total']['protocol_res'])
        iddlist = []
        iddlist.append(idd)
        check = cur.execute('SELECT * FROM houses WHERE id=?', iddlist)
        res = check.fetchone()
        if res:
            print('already exists')
        else:
            insert = cur.execute('INSERT INTO houses (id, street, house_nbr, house_additional, total_votes, total_za, meeting) values (?, ?, ?, ?, ?, ?, ?)', [idd, adress_street, adress_house, adress_building, totalvotes, aye, meetinghappened])
            print('added ' + str(idd))
    except ValueError:
        print('no data for id '+ str(idd))
        jsonerror.append(idd)
    except:
        print('unknown eggog')
        unknownerror.append(idd)

jsonerror = []
unknownerror = []
with open('/home/deb/mosres.txt') as fc:
    mosres = fc.read().splitlines()

conn = sqlite3.connect('/home/deb/renovation.db')
cur = conn.cursor()

for house in mosres:
    gethouseinfo(house)

conn.commit()
conn.close()

if jsonerror:
    with open('/home/deb/jsonerror.txt', 'w') as f:
        for item in jsonerror:
            f.write('{}\n'.format(item))
            
if unknownerror:
    with open('/home/deb/unknownerror.txt', 'w') as f:
        for item in unknownerror:
            f.write('{}\n'.format(item))

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

Все результаты (отсортированные от малого до великого, чтобы наглядно посмотреть процент за и против, икс — дома, игрек — проценты за, зелёная линия — для удобства, отсекает 66 процентов, которые надо было преодолеть):



Распределение голосов «за»:



Всё это хорошо, но нас же интересовала явка. И вот тут становится тяжело. Дело в том, что нормального, простого, централизованного ресурса с количеством квартир по адресу нет. Возможно, оно есть у 2ГИС, по крайней мере, в примерах платной выгрузки информации количество квартир есть, но — платно? Это же не наш метод! Мы пойдём другим путём.

Нещадный гуглинг и яндекс указал на сайт tvoyadres.ru/doma, где дома, казалось бы, есть, зачастую — с информацией по квартире. Но как их собирать? В идеале нужно сначала собрать весь список домов (ну хорошо, хотя бы улиц), на которые есть данные, а потом попытаться связать адреса в нашей базе данных, взятые в формате мэрии, с адресами в формате этого сайта, а потом вытащить у тех, что удалось связать, квартиры. Наверное, стоит начать с улиц? tvoyadres.ru/ulitsy — но перебирать 200 страниц, скрапя и обрабатывая каждую выдачу, очень муторно. Может быть, удастся найти и тут какой-нибудь апи?

Успех ждал на странице города, где есть не только список улиц, но и кнопка «Ещё улицы»: tvoyadres.ru/moskovskaya-oblast/goroda/551



Ага! Запрос вида
http://tvoyadres.ru/js/street.php?region=81&city=Москва&count=2073&_=1499809159225
даёт нам список улиц со ссылками на них (а в ссылки — айдишник). Отлично, осталось понять, что значат символы в запросе. Регион, очевидно, мы трогать не будем, город, тоже. Попробуем убрать последнее непонятное, оставив лишь tvoyadres.ru/js/street.php?region=81&city=Москва&count=2073 — результат такой же. ОК, нажмём ещё раз на кнопку — увидим, что пошёл такой же запрос, но с каунтом на 100 меньше. Поиграем вручную с этим параметром.

0 — возвращается ошибка. 1 — возвращается одна улица. 2 — возвращается две улицы, причём одну мы уже видели. 100 — возвращается 100 улиц. 200 — возвращается ещё 100 улиц. Начинали мы с 2073 — попробуем 2173? Да, это те самые первые сто улиц, что отображались на странице города. 2174?

Critical Error

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-1, 100' at line 1

Оп-па. Ну, похоже, count идёт в LIMIT SELECT-запроса, причём в лимите всегда выдаётся 100 строк, а вот строка, с которой начинать, вычисляется как count минус 2173. Кстати, вроде довольно секурно — как сделать тут sql-инъекцию я не придумал, оно же не передаётся, а вычисляется, и если сунуть туда не число — банально падает. Ну да ладно. Результат есть. Отлично, теперь к делу.

Всё даже проще, чем обычно:

def getstreets(num):
    r = requests.get(url + str(num))
    results = r.json()
    result = results['string']
    return(result)

for i in range(1, 2272, 100):
    totalres += getstreets(i)


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

sids = re.findall('ulitsy\/(.*?)">(.*?)<\/a>', totalres)
#sids = streets with ids
streetsdict = {}

for i in range(len(sids)):
    key = sids[i][1]
    value = sids[i][0]
    streetsdict[key] = value

А вот дальше нам предстоит доставать дома со страниц улиц, иными словами — работать над кучей куч html. Такие кучу регулярными выражениями пытаться отпарсить — себе дороже. Поэтому познакомимся с BeautifulSoup.

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

import re
from bs4 import BeautifulSoup

def gethouses(num):
    r = requests.get('http://tvoyadres.ru/moskovskaya-oblast/moskva/ulitsy/' + str(num) + '/')
    results = r.text
    soup = BeautifulSoup(results, 'html.parser')
    ul = soup.find("ul", {"class": "next"})
    houses = []
    try:
        for li in ul.find_all("li"):
            urly = li.a['href']
            urly = re.search('doma\/(.*)\/', urly).group(1)
            houses.append([li.get_text(), urly])
        return(houses)
    except:
        print('None')
        return('None')

totalyres = {}

for key in sids:
    num = sids[key]
    totalyres[num] = gethouses(num)

Тут нам приходит в голову сразу две вещи. Первая — надо бы сделать не дикт, в котором на каждую улицу приходится список, в котором каждое значение — список с названием дома и его айдишником, а дикт со вложенными диктами. Это можно превратить простым loop'ом, не будем заострять внимание, но назовём такой дикт totre — да, фантазия под конец совсем меня покинула. Извините.

Вторая — а ведь юрл каждого дома включает в себя не только айдишник, но и транслитерацию улицы! Пример.

for key in totre:
    urlo = 'http://tvoyadres.ru/moskovskaya-oblast/moskva/ulitsy/' + key + '/'
    ra = requests.get(urlo)
    try:
        streetname = re.search('
  • /docs.python.org/3/library/difflib.html">difflib, благо в питон он встроен. Но мало надеяться на диффлиб, нужно будет сделать проверку пользователем, потому что частотность и схожесть это, конечно, хорошо, но нам нужно избежать глупых ошибок. В общем, смотрим на форматы, замечаем, что где-то нет букв ё как класс, где-то слово «улица» из названия улицы убрано, и делаем такое вот:

    conn = sqlite3.connect('renovation.db')
    cur = conn.cursor()
    streets = cur.execute('SELECT DISTINCT street FROM houses order by street asc')
    streeets = streets.fetchall()
    conn.close()
    
    exactmatches = {}
    keyslist = []
    for key in sids.keys():
        keyslist.append(key)
    
    def glue(maxres=3, freq=0.6):
        for each in streeets:
            eachnoyo = each[0].replace('ё', 'е')
            diffres = difflib.get_close_matches(eachnoyo, keyslist, maxres, freq)
            if each[0] not in exactmatches.keys():
                if len(diffres) == 1:
                    print(each[0] + ': ' + diffres[0])
                    notcompleted = False
                    while notcompleted == False:
                        inp = input('Correct? y/n ')
                        if inp == 'y':
                            notcompleted = True
                            exactmatches[each[0]] = sids[diffres[0]]
                        elif inp == 'n':
                            notcompleted = True
                        else:
                            print('Incorrect input, try again')
                elif len(diffres) == 0:
                    print('No matches for ' + each[0])
                elif len(diffres) > 1:
                    print(each[0] + ': ' + str(diffres))
                    notcompleted = False
                    while notcompleted == False:
                        inp = input('List number? Or n ')
                        try:
                            listnum = int(inp)
                        except:
                            listnum = None
                        if inp == 'n':
                            notcompleted = True
                        elif listnum in range(0, len(diffres)):
                            notcompleted = True
                            exactmatches[each[0]] = sids[diffres[0]]
                        else:
                            print('Incorrect input, try again')
        with open('exactmatches.json', 'w') as f:
            json.dump(exactmatches, f, ensure_ascii=False) 

    Сидим в консоли, смотрим выдачу, нажимаем кнопки. Когда прошли весь цикл — запускаем функцию с более щадящими параметрами, например, glue(10, freq=0.4).



    Мне терпения хватило на 506 улиц из 700 с копейками — по-моему, отличный результат, а главное, статистически значимый (скорее всего).

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

    conn = sqlite3.connect('renovation.db')
    cur = conn.cursor()
    allhouses = cur.execute('SELECT * FROM houses WHERE flats IS NULL ORDER BY id')
    allhousesres = allhouses.fetchall()
    
    url2 = 'http://tvoyadres.ru/moskovskaya-oblast/moskva/'
    
    
    def getnumberofflats(streetname, houseid):
        urlo = url2 + str(streetname) + '/doma/' + str(houseid) + '/'
        r = requests.get(urlo)
        results = r.text
        numbe = re.search('Количество квартир<\/span> (\d*)<', results).group(1)
        return numbe
    
    def gluehousesnumbers(freq=3, ratio=0.6):
        for house in allhousesres:
            if house[1] in exactmatches.keys():
                housenbr = house[2].replace('дом', '')
                if house[3]:
                    housenbr = housenbr + ' ' + house[3]
                housenbr = housenbr.lower()
                diffres = difflib.get_close_matches(housenbr, totre[exactmatches[house[1]]].keys(), freq, ratio)
                if len(diffres) == 1:
                    print(housenbr + ': ' + diffres[0])
                    notcompleted = False
                    while notcompleted == False:
                        inp = input('Correct? y/n ')
                        if inp == 'y':
                            notcompleted = True
                            try: 
                                flatsnumber = getnumberofflats(totre[exactmatches[house[1]]]['streetname'], totre[exactmatches[house[1]]][diffres[0]])
                                insertion = cur.execute('UPDATE houses SET flats = ? WHERE id = ?', [flatsnumber, house[0]])
                            except:
                                print('weird, no flat number for ' + str(house))
                        elif inp == 'n':
                            notcompleted = True
                        else:
                            print('Incorrect input, try again')
                elif len(diffres) > 1:
                    print(housenbr + ': ' + str(diffres))
                    notcompleted = False
                    while notcompleted == False:
                        inp = input('List number? Or n ')
                        try:
                            listnum = int(inp)
                        except:
                            listnum = None
                        if inp == 'n':
                            notcompleted = True
                        elif listnum in range(0, len(diffres)):
                            notcompleted = True
                            try:
                                flatsnumber = getnumberofflats(totre[exactmatches[house[1]]]['streetname'], totre[exactmatches[house[1]]][diffres[0]])
                                insertion = cur.execute('UPDATE houses SET flats = ? WHERE id = ?', [flatsnumber, house[0]])
                            except:
                                print('weird, no flat number for ' + str(house))
                        else:
                            print('Incorrect input, try again')
    
    conn.commit()
    conn.close()
    

    Продолжаем развлекаться. Главное — не забывать закоммитить изменения после каждого прогона функции. Я не стал добавлять коннект и коммит в сами функции, чтобы не теребить постоянно базу данных.

    Да, это довольно утомительно. Но, опять же, если отдать всё на откуп диффлибу — будут дурацкие ошибки, как на скриншоте, где он считает «35б» ближе к «35», чем к «35 'б'». Это, конечно, не ошибка диффлиба, но, если честно, я потратил бы больше времени на поск идеального запроса, а потом бы всё равно где-нибудь споткнулся. Лучшее с подтверждением пользователя, увереннее.



    Итого: количество квартир есть для 3592 из примерно 4500 домов! Отличный результат (сам себя не похвалишь — никто не похвалит). Но, конечно, если подтверждать так много совпадений — будут ошибки.



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

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

    Округляем до ближайшего целого:



    Округляем до ближайшего, кратного пяти:



    В общем и целом, за исключением пары антипиков в районе 80% явки, или, если смотреть с округлением пожиже, в районах 30%, 40% и 80%, в целом, явка на результат не влияла. Разве что 100%-ая явка удивительным образом всегда давала 100%-й результат. А в среднем явка была 58,7%.

    Стоило ли оно того? Для меня да, узнал много нового. А для читателя? Ну, читателю я выкладываю саму базу данных.

    Может быть, вы сможете сделать с этими данными что-то поинтереснее.
    Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333540/


Метки:  

Разработка для Sailfish OS: Тестирование QML-кода, зависящего от C++ в Sailfish OS

Понедельник, 17 Июля 2017 г. 18:51 + в цитатник
Здравствуйте! Данная статья является продолжением цикла статей, посвященных разработке для мобильной платформы Sailfish OS и их тестированию. Одна из предыдущих статей была посвящена тестированию QML-компонентов приложения. Однако, часто разработчики сталкиваются с потребностью написания собственных компонентов на языке C++ для использования функционала, недоступного из QML, или для улучшения производительности. Об этом также уже было написано. Тестирование таких компонентов отличается от тестирования уже существующих. В данной статье мы расскажем, как тестировать собственные QML-компоненты, написанные на языке C++.

Тестируемое приложение


В качестве приложение возьмём то же самое, что брали в предыдущей статье — приложение-счётчик (исходный код приложения доступен на GitHub). В текущей реализации значение счётчика хранится в свойстве страницы. Это значение изменяется при нажатии на кнопки «add» и «reset» и используется для отображения на виде.

Мы изменим приложение таким образом, чтобы значение хранилось и изменялось с помощью кода, написанного на C++. Добавим класс Counter, имеющий следующий вид:

// counter.h
#include 

class Counter : public QObject {
    Q_OBJECT
    Q_PROPERTY(int count READ count NOTIFY countChanged)
private:
    int m_count = 0;
public:
    int count();
    Q_INVOKABLE void incrementCount();
    Q_INVOKABLE void resetCount();
signals:
    void countChanged();
};


// counter.cpp
int Counter::count() {
    return m_count;
}

void Counter::incrementCount() {
    m_count++;
    emit countChanged();
}

void Counter::resetCount() {
    m_count = 0;
    emit countChanged();
}

Данный класс унаследован от QObject и содержит в своём теле макрос Q_OBJECT, что позволяет экспортировать его в QML. Класс содержит единственное свойство count, доступное только для чтения. Для изменения значения этого свойства используются методы incrementCount() и resetCount(). Методы помечены макросом Q_INVOKABLE, для того, чтобы их можно было вызывать из QML.

Для использования классов, написанных на C++ в QML, необходимо зарегистрировать класс как QML-тип. Обычно это делается в теле функции main() приложения. В данном случае мы этого сделать не можем. Дело в том, что qmltestrunner не вызывает главную функцию приложения при запуске тестов.

QML-плагин


Решить проблему, описанную выше, можно с помощью QML-плагина. Идея состоит в том, чтобы выделить C++ код в библиотеку и использовать её при запуске приложения и тестов. Регистрация QML-типов в данном случае переносится в QML-плагин.

Для того, чтобы создать плагин, необходимо разделить проект на две части. Под каждую из частей создадим директории с подпроектами, содержащими файл *.pro с названием, соответствующим названию директории. Первый подпроект назовём core, он будет содержать весь C++ код, кроме файла *.cpp с функцией main(). Второй — app, он будет содержать QML-файлы, файл *.desktop и файлы с переводами. Сюда же поместим *.cpp файл с функцией main().

Файл core.pro выглядит следующим образом:

TEMPLATE = lib

TARGET = core

CONFIG += qt plugin c++11

QT += qml\
    quick\

HEADERS += \
    counter.h

SOURCES += \
    counter.cpp

DISTFILES += qmldir

uri = counter.cpp.application.Core

qmldir.files = qmldir
installPath = /usr/lib/counter-cpp-application/$$replace(uri, \\., /)
qmldir.path = $$installPath
target.path = $$installPath
INSTALLS += target qmldir

В файле core.pro необходимо использовать TEMPLATE = lib, чтобы подпроект использовался как библиотека. Целью библиотеки (TARGET) указываем её название, т.е. core. В CONFIG обязательно добавляем plugin, чтобы указать, что библиотека подключается в виде плагина. В DISTFILES необходимо добавить путь к файлу qmldir, который должен быть расположен в директории core и содержать название модуля и плагина. В нашем случае будет следующее содержимое этого файла:

module counter.cpp.application.Core
plugin core

В конце файла core.pro необходимо указать путь к файлам библиотеки и к файлу qmldir. Библиотеку помещаем в директорию /usr/lib/, а путь к плагину указываем counter/cpp/application/Core.

Файл app.pro содержит конфигурацию самого приложения. Здесь указывается целевое приложение, пути к файлам qml, иконок и переводов. Сюда же добавляем *.cpp файл с главной функцией. В нашем примере файл имеет следующий вид:

TARGET = counter-cpp-application

CONFIG += sailfishapp \
          sailfishapp_i18n \
          c++11

SOURCES += src/counter-cpp-application.cpp

OTHER_FILES += qml/counter-cpp-application.qml \
    qml/cover/CoverPage.qml \
    translations/*.ts \
    counter-cpp-application.desktop

TRANSLATIONS += translations/counter-cpp-application-de.ts

SAILFISHAPP_ICONS = 86x86 108x108 128x128 256x256

DISTFILES += \
    qml/CounterCppApplication.qml \
    qml/pages/CounterPage.qml 

Теперь необходимо изменить *.pro файл проекта, чтобы он включал в себя два созданных нами подпроекта. Для этого добавим в данный файл TEMPLATE = subdirs и добавим наши директории как подпроекты. В таком случае по очереди будут собраны подпроекты, находящиеся в данных директориях. Здесь же необходимо оставить добавление файлов проекта из директории rpm, так как они всегда должны находиться в корне основного проекта. Для нашего приложения это выглядит так:

TEMPLATE = subdirs

OTHER_FILES += $$files(rpm/*)

SUBDIRS += \
    app \
    core

app.depends = core

Здесь же мы указали, что подпроект app зависит от core.

Теперь, когда структура проекта подготовлена, можно приступать к реализации плагина. Необходимо создать C++ класс, который мы назовём CorePlugin. Класс должен быть унаследован от QQmlExtensionPlugin. В нём будет производиться регистрация типов и инициализация движка.

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

  • registerTypes(const char *uri): нужен для регистрации наших QML-типов. В качестве параметре методу передаётся URI нашего плагина, который указывается в файле qmldirs.
  • initializeEngine(QQmlEngine *engine, const char *uri): нужен для инициализации движка нашего приложения. Первый параметр является QML-движком, с помощью которого можно настроить приложение, второй — URI плагина.

В нашем случае пока достаточно только первого метода. Используем его для регистрации класса Counter. В тело метода registerTypes() поместим следующее:

qmlRegisterType(uri, 1, 0, "Counter");

В угловых скобках указывается имя регистрируемого класса. Первым параметром передаётся URI плагина. Вторым и третьим параметрами передаются старший и младший номера версий. Четвёртым параметром передаётся имя, под которым будет доступен наш класс из QML. Теперь можно использовать тип Counter в нашем приложении.

Использование собственного QML-компонента


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

int main(int argc, char *argv[]) {
    return SailfishApp::main(argc, argv);
}

Изменим код функции main() для того, чтобы указать путь к библиотеке:

int main(int argc, char *argv[]) {
    QGuiApplication* app =  SailfishApp::application(argc, argv);
    QQuickView* view = SailfishApp::createView();
    view->engine()->addImportPath("/usr/lib/counter-cpp-application/");
    view->setSource(SailfishApp::pathTo("qml/counter-cpp-application.qml"));
    view->showFullScreen();
    QObject::connect(view->engine(), &QQmlEngine::quit, app, &QGuiApplication::quit);
    return app->exec();
}

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

За основу возьмём файл CounerPage.qml из предыдущей статьи. Добавим наш плагин следующим образом:

import counter.cpp.application.Core 1.0

Здесь используется URI, ранее указанный в файле qmldirs, и версии 1.0 указанные при регистрации типа. Для использования типа добавим его внутри страницы:

Counter {
    id: counter
}

Теперь вместо изменения значения свойства count будем вызывать методы counter.increment() и counter.reset() при добавлении и сбросе счётчика соответственно.
Код тестов при этом остаётся тем же самым, что и в предыдущей статье, так как мы не меняли визуальные компоненты.

Запуск тестов


Запуск тестов происходит с помощью qmltestrunner. Так как часть кода перешла в QML-плагин, то нам необходимо вручную указывать путь к нему. Для этого используется переменная QML2_IMPORT_PATH, которой присваивается путь к файлам библиотеки перед запуском тестов. В итоге для рассматриваемого приложение это будет выглядеть так:

QML2_IMPORT_PATH=/usr/lib/counter-cpp-application/ /usr/lib/qt5/bin/qmltestrunner -input /usr/share/counter-cpp-application/tests/

Код тестов и вывод результатов остаётся тем же самым, что и в предыдущей статье:

********* Start testing of qmltestrunner ********* 
Config: Using QtTest library 5.2.2, Qt 5.2.2 
PASS : qmltestrunner::Counter tests::initTestCase() 
PASS : qmltestrunner::Counter tests::test_counterAdd() 
PASS : qmltestrunner::Counter tests::test_counterReset() 
PASS : qmltestrunner::Counter tests::cleanupTestCase() 
Totals: 4 passed, 0 failed, 0 skipped 
********* Finished testing of qmltestrunner *********


Заключение


Тестирование собственных QML-компонентов отличается от тестирования уже имеющихся в библиотеке QtQuick. Для реализации возможности их тестирования нам пришлось выделить весь C++ код в QML-плагин и подключать его как библиотеку. В результате код для тестирования не отличается от того, который тестировал бы стандартные QML-компоненты. Тем не менее сам проект потребовал значительных изменений. Приложение в таком виде уже можно использовать при публикации в магазине. Исходный код примера доступен на GitHub.

Технические вопросы можно также обсудить на канале русскоязычного сообщества Sailfish OS в Telegram или группе ВКонтакте.

Автор: Сергей Аверкиев
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/325936/


Метки:  

Книга «Автостопом по Python»

Понедельник, 17 Июля 2017 г. 18:10 + в цитатник
image Привет, Хаброжители! Мы издали книгу, составленную на основе одноименного онлайнового руководства и содержащую наработки многочисленных профессионалов и энтузиастов, знающих, что такое Python и чего вы от него хотите.

Это руководство не предназначено для того, чтобы обучить вас языку Python (мы приведем ссылки на множество хороших ресурсов, которые помогут вам в этом), оно скорее представляет собой (безапелляционное) руководство от специалиста, где рассматриваются популярные инструменты и лучшие практики нашего сообщества. Аудитория этой книги разнообразна — от новичков до программистов Python среднего уровня, которые либо хотели бы внести свой вклад в развитие программного обеспечения (ПО) с открытым исходным кодом, либо начинают карьеру или создают компанию и собираются писать на Python (однако для рядовых пользователей Python также будут полезными часть I и глава 5).


В первой части книги мы поговорим о том, как выбрать текстовый редактор или интерактивную среду разработки, которые подойдут вам для работы (например, читатели, которые часто используют язык Java, могут предпочесть Eclipse с встроенным плагином для Python). Кроме того, рассматриваются другие интерпретаторы, удовлетворяющие те потребности, в отношении которых вы даже предположить не могли, что Python может с этим справиться (например, существует реализация MycroPython, основанная на чипе ARM Cortex-M4). Во второй части демонстрируется «питонский» стиль выделения кода примеров, принятый в сообществе, работающем с открытым исходным кодом. Надеемся, этот стиль вдохновит вас на углубленное изучение и экспериментирование с открытым кодом. В третьей части кратко рассматривается широкий перечень библиотек, наиболее часто используемых в сообществе Python, — это поможет вам получить представление о том, какие задачи Python может решать в текущий момент.

Отрывок из книги. Непрерывная интеграция


Никто не опишет процесс непрерывной интеграции лучше, чем Мартин Фаулер (Martin Fowler).

Фаулер выступает за использование правил хорошего тона при проектировании ПО. Он один из главных сторонников непрерывной интеграции. Эта цитата взята из его статьи о непрерывной интеграции. Он провел серию семинаров, посвященных разработке через тестирование и отношению к экстремальной разработке, вместе с Дэвидом Хайнемайером Хэнссоном (David Heinemeier Hansson, создатель Ruby on Rails) и Кентом Бэком (Kent Beck, инициатор движения экстремального программирования (XP), одним из основных принципов которого является непрерывная разработка).

Тремя наиболее популярными инструментами для непрерывной интеграции в данный момент являются Travis-CI, Jenkins и Buildbot (перечислены в следующих разделах). Они часто используются с Tox, инструментом Python для управления virtualenv и тестами из командной строки. Travis помогает работать с несколькими интерпретаторами Python на одной платформе, а Jenkins (самый популярный) и Buildbot (написан на Python) могут управлять сборками на нескольких машинах. Многие также используют Buildout (рассмотрен в подразделе «Buildout» раздела «Инструменты изоляции» главы 3) и Docker (рассмотрен в подразделе «Docker» там же) для быстрой и частой сборки сложных сред для батареи тестов.

Tox. Tox — это инструмент автоматизации, предоставляющий функциональность упаковки, тестирования и развертывания ПО, написанного на Python, из консоли или сервера непрерывной интеграции. Является общим инструментом командной строки для управления и тестирования, который предоставляет следующие функции:

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

Вы можете установить Tox с помощью pip:
$ pip install tox

Системное администрирование


Инструменты, показанные в этом разделе, предназначены для наблюдения за системами и управления ими (автоматизация сервера, наблюдение за системами и управление потоком выполнения).

Travis-CI


Travis-CI — распределенный сервер непрерывной интеграции, позволяющий создавать тесты для проектов с открытым исходным кодом бесплатно. Предоставляет несколько рабочих процессов, которые запускают тесты Python, и бесшовно интегрируется с GitHub. Вы даже можете указать ему оставлять комментарии для ваших запросов на включение, если этот конкретный набор из менений сломает сборку. Поэтому, если вы размещаете свой код на GitHub, Travis-CI — отличное средство, чтобы начать использовать непрерывную интеграцию. Travis-CI может собрать ваш код на виртуальной машине, на которой запущены Linux, OS X или iOS.

Для того чтобы начать работу, добавьте файл в расширением .travis.yml в ваш репозиторий. В качестве примера его содержимого приведем следующий код:
language: python
python:
   - "2.6"
   - "2.7"
   - "3.3"
   - "3.4"
script: python tests/test_all_of_the_units.py
branches:
   only:
      - master

Этот код указывает протестировать ваш проект для всех перечисленных версий Python путем запуска заданного сценария, сборка будет выполнена только для ветки master. Существует множество доступных параметров вроде уведомлений, предыдущих и последующих шагов и многих других. Для того чтобы использовать Tox вместе с Travis-CI, добавьте сценарий Tox в ваш репозиторий и измените строку с конструкцией script:; файл должен выглядеть так:
install:
- pip install tox
script:
- tox

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

Jenkins


Jenkins CI — это расширяемый движок непрерывной интеграции, в данный момент он считается самым популярным. Работает на Windows, Linux и OS X, его можно подключить к «каждому существующему инструменту управления исходным кодом». Jenkins является сервлетом Java (эквивалент приложений WSGI в Java), который поставляется с собственным контейнером сервлетов, что позволяет вам запускать его с помощью команды java --jar jenkins.war. Для получения более подробной информации обратитесь к инструкциям по установке Jenkins; на странице Ubuntu содержится информация о том, как разместить Jenkins на базе обратного прокси Apache или Nginx.

Вы взаимодействуете с Jenkins с помощью информационной панели или его RESTful API1, основанного на НТТР (например, по адресу http://myServer:8080/api), что означает, что можно использовать HTTP для того, чтобы общаться с Jenkins с удаленных машин. Например, взгляните на Jenkins Dashboard для Apache или Pylons.

Для взаимодействия с Jenkins API в Python наиболее часто применяется python-jenkins, созданный командой OpenStack2. Большинство пользователей Python конфигурируют Jenkins так, чтобы он запускал сценарий Tox как часть процесса сборки. Для получения более подробной информации обратитесь к документации по адресу, где рассказывается об использовании Tox для Jenkins, а также к руководству по настройке Jenkins для работы с несколькими машинами.

Buildbot


Buildbot — это система Python, предназначенная для автоматизации цикла компиляции/тестирования, проверяющего изменения кода. Похож на Jenkins тем, что опрашивает менеджер системы контроля версий на наличие изменений, выполняет сборку и тестирование вашего кода на нескольких компьютерах в соответствии с вашими инструкциями (имеет встроенную поддержку для Tox), а затем говорит вам, что произошло. Он работает на базе веб-сервера Twisted. Если вам нужен пример того, как будет выглядеть веб-интерфейс, взгляните на общедоступную информационную панель buildbot от Chromium.

Поскольку Buildbot написан на чистом Python, его можно установить с помощью pip:
$ pip install buildbot

Версия 0.9 имеет REST API, но она все еще находится на стадии бета-тестирования, поэтому вы не сможете ее использовать, если только явно не укажете номер версии (например, pip install buildbot==0.9.00.9.0rc1). Buildbot имеет репутацию самого мощного и самого сложного инструмента непрерывной интеграции. Для начала работы с ним обратитесь к этому отличному руководству.

Об авторах


Кеннет Ритц (Kenneth Reitz) — владелец продукта Python в Heroku и Fellow в Python Software Foundation. Он широко известен благодаря своим проектам с открытым исходным кодом, а особенно благодаря Requests: HTTP for Humans.

Таня Шлюссер (Tanya Schlusser) ухаживает за своей матерью, у которой болезнь Альцгеймера, работает независимым консультантом, используя данные метрик для принятия стратегических решений. Она потратила множество часов на обучение студентов и корпоративных клиентов работе с данными.

» Более подробно с книгой можно ознакомиться на сайте издательства
» Оглавление
» Отрывок

Для Хаброжителей скидка 25% по купону — Python
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333498/


Метки:  

[Перевод] Кроссплатформенный IoT: Использование Azure CLI и Azure IoT Hub

Понедельник, 17 Июля 2017 г. 17:57 + в цитатник
Представляем первую статью из цикла «Кроссплатформенный IoT». При прочтении заголовка у вас мог возникнуть вопрос: какое отношение имеет CLI к IoT Hub? Всё просто, разработчики представили модуль, который позволяет управлять операциями IoT Hub из командной строки. Под катом вы узнаете как активировать поддержку Azure IoT Hub в Azure CLI, создать и управлять им далее.



Цикл статей «Кроссплатформенный IoT»


1. Использование Azure CLI и Azure IoT Hub
2. Loading…

Azure CLI — полезное дополнение к набору кроссплатформенных средств управления облачными ресурсами. Инструмент развивается настолько быстро, что иногда мне кажется, что он лучше, чем CLI версии PowerShell :). На сегодняшний день есть две версии Azure CLI:
  • Версия Azure CLI на node.js — инструмент, поддерживающий все ресурсы Azure — группы ресурсов, виртуальные машины, учетные записи хранения и так далее.
  • Новая версия на базе Python специально для лучшей поддержки платформ Unix/Linux — Azure CLI 2.0. Мы будем использовать Azure CLI 2.0.

Функциональные возможности двух версий приблизительно одинаковы, они обе подойдут для запуска модулей IoT. Здесь доступна краткая информация о задачах, для решения которых и создавался Azure CLI 2.0.

Начнём с установки компонентов IoT для Azure CLI, затем посмотрим, как использовать CLI для создания и управления IoT Hub.

Если вы еще не установили Azure CLI 2.0, вы можете сделать это отсюда. По ссылке лежат инструкции по установке CLI на любую ОС; мы будем использовать MacOS. Скрипты Python обеспечивают установку зависимостей, а также задают путь для команды «az» из терминала.
Скрипт дополнит ~/.bashrc, что, как я заметил, плохо взаимодействует с терминалом MacOS. Чтобы вы могли использовать псевдоним «az» для всех команд Azure CLI, нужно добавить следующую переменную среды в вашу конфигурацию ~/.bash_profile. Для изменения конфигурации вводим в bash nano ~/.bash_profile, после чего сохраняем настройки:
export PATH=\~/bin:$PATH

Не отображается .bash_profile?


Если .bash_profile недоступен (это характерно для MacOS), вы можете просто создать его, с помощью:
cd ~/
touch .bash_profile

Чтобы убедиться, что Azure CLI работает, откройте терминал и введите:
az --version

Откроется список всех компонентов, установленных в составе CLI:
acs (2.0.0)
appservice (0.1.1b5)
batch (0.1.1b4)
cloud (2.0.0)
component (2.0.0)
configure (2.0.0)
container (0.1.1b4)
core (2.0.0)
documentdb (0.1.1b2)
feedback (2.0.0)
keyvault (0.1.1b5)
network (2.0.0)
nspkg (2.0.0)
profile (2.0.0)
redis (0.1.1b3)
resource (2.0.0)
role (2.0.0)
sql (0.1.1b5)
storage (2.0.1)
vm (2.0.0)
Python (Darwin) 2.7.10 (default, Jul 30 2016, 19:40:32) 
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)]

Имейте ввиду, что IoT-модуль не установлен по умолчанию. Установим его:
az login
az account set --subscription  
az component update --add iot
az provider register -namespace Microsoft.Devices

Эти команды авторизуют вас и соотнесут учётную запись с нужной подпиской Azure, установят и зарегистрируют IoT-модуль. az –version должен дать результат с новым модулем.
acs (2.0.0)
appservice (0.1.1b5)
......
iot (0.1.1b3)
......

Далее IoT-модуль подразделяется на две группы, device и hub:
  • Группа hub — для команд, относящихся к IoT Hub. Включает команды: создать, обновить, удалить, задать список, показать строку подключения, отобразить квоту и так далее.
  • Группа device — для команд, относящихся к операциям с устройствами. Включает команды: создать, удалить, задать список, обновить, показать, показать строку подключения, импортировать, экспортировать.

Хелп к командам: az iot device -h или az iot hub -h.

Идём дальше – создаём группу ресурсов и новый IoT Hub.
az group create --name yourresourcegroupname --location westus
az iot hub create --name youriothubname --location yourlocation --sku S1 --unit 1 --resource-group yourresourcegroupname 

Я указал SKU S1, но IoT Hub можно использовать в бесплатном режиме – F1 (доступные значения: {F1,S1,S2,S3}). Кроме того, unit обозначает количество юнитов, которые вы хотите создать с помощью IoT Hub. Также указывается регион, в котором будет создан IoT Hub. Вы можете пропустить этот пункт — IoT Hub будет размещён в регионе с группой ресурсов. Список доступных регионов (на момент написания данного текста): {westus,northeurope,eastasia,eastus,westeurope,southeastasia,japaneast,japanwest,australiaeast,australiasoutheast,westus2,westcentralus}.
Если все прошло успешно, вы должны увидеть вот такой ответ:
{
  "etag": "AAAAAAC2NAc=",
  "id": "/subscriptions/yournamespace/providers/Microsoft.Devices/IotHubs/youriothubname",
  "location": "westus",
  "name": "youriothubname",
  "properties": {
       ....
      }
    },
    ... 
''   "type": "Microsoft.Devices/IotHubs"
}

Мы только что создали IoT Hub из командной строки на Mac! В следующей публикации я расскажу, как использовать IoT Hub для добавления устройств и выполнения других операций.

И ещё несколько полезных команд Azure IoT CLI


Чтобы посмотреть конфигурацию IoT Hub, достаточно ввести az iot hub list -g yourresourcegroupname — должен появиться список всех IoT Hub, созданных в вашей группе ресурсов. Если вы опустите группу ресурсов, отобразятся все инстансы IoT Hub в подписке. Для просмотра подробной информации о конкретном IoT Hub укажите: az iot hub show -g yourresourcegroupname --name yourhubname.

IoT Hub по умолчанию создаёт набор политик, которые могут использоваться для доступа. Для просмотра списка политик введите az iot hub policy list --hub-name youriothubname. Политики — это важный элемент работы IoT Hub. Всегда придерживайтесь принципа «наименьших привилегий» и выбирайте политику, соответствующую текущей операции. Например, политика iothubowner предоставляет права администратора IoT Hub и не должна использоваться, в частности, для подключения устройства.

Чтобы просто получить строки подключения для созданных IoT Hub, введите az iot hub show-connection-string -g yourresourcegroupname.

Учтите, что по умолчанию приведенная выше команда использует строку подключения для политики iothubowner, которая предоставляет полное управление вашим IoT Hub. Рекомендуется задавать детализированные политики. Они гарантируют наименьшие права доступа. Для этого воспользуйтесь опцией --policy-name и укажите название политики.

Также можно использовать команды az iot device для создания device; вместо этого для демонстрации этих функций мы воспользуемся IoT Hub Explorer. IoT Hub Explorer предоставляет несколько дополнительных команд. Мне кажется, что все функциональные возможности IoT Hub Explorer войдут в будущую версию IoT-компонента для Azure CLI.

Что внутри Azure CLI?


Одно из достоинств Azure CLI состоит в том, что для создания ресурсов и объектов в Azure он использует REST API. Если хочется понять, что происходит внутри, и отладить процессы, можно использовать опцию -debug, которая предоставляет трассировку всех производимых вызовов и любых сопутствующих исключений, которые могли произойти во время обработки. Например, для команды такого типа:
az iot hub show-connection-string -g yourresourcegroupname --debug"

должно отобразиться примерно следующее:
Command arguments ['iot', 'hub', 'show-connection-string', '-g', 'yourrgname']
Current active cloud 'AzureCloud'
{'active_directory': 'https://login.microsoftonline.com',
 'active_directory_graph_resource_id': 'https://graph.windows.net/',
 'active_directory_resource_id': 'https://management.core.windows.net/',
 'management': 'https://management.core.windows.net/',
 .......
'storage_endpoint': 'core.windows.net'}
Registered application event handler 'CommandTableParams.Loaded' at 
Registered application event handler 'CommandTable.Loaded' at 
Successfully loaded command table from module 'iot'.
..........
g': 'gzip, deflate'
msrest.http_logger :     'Accept': 'application/json'
msrest.http_logger :     'User-Agent': 'python/2.7.10 (Darwin-16.4.0-x86_64-i386-64bit) requests/2.13.0 msrest/0.4.6 msrest_azure/0.4.7 iothubclient/0.2.1 Azure-SDK-For-Python AZURECLI/2.0.0'
msrest.http_logger :     'Authorization': 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImEzUU4wQlpTN3M0bk4tQmRyamJGMFlfTGRNTSIsImtpZCI6ImEzUU4wQlpTN3M0bk4tQmRyamJGMFlfTGRNTSJ9.eyJhdWQiOiJodHRwczovL21hbmFnZW1lbnQuY29yZS53aW5kb3dzLm5ldC8iLCJpc3MiOiJodHRwcz0cy53aW5kb3dzLm5ldC83MmY5ODhiZi04NmYxLTQxYWYtOTFhYi0yZDdjZDAxMWRiNDcvIiwiaWF0IjoxNDg5NjEzODc5LCJuYmYiOjE0ODk2MTM4NzksImV4cCI6MTQ4OTYxNzc3OSwiX2NsYWltX25hbWVzIjp7Imdyb3VwcyI6InNyYzEifSwiX2NsYWltX3NvdXJjZXMiOnsic3JjMSI6eyJlbmRwb2ludCI6Imh0dHBzOi8vZ3JhcGgud2luZG93cy5uZXQvNzJmOTg4YmYtODZmMS00MWFmLTkxYWItMmQ3Y2QwMTFkYjQ3L3VzZXJzL2UyZTNkNDdlLTRiYzAtNDg1Yy04OTE1LWYyMDVkYzRlODY5YS9nZXRNZW1iZXJPYmplY3RzIn19LCJhY3IiOiIxIiwiYWlvIjoiQVFBQkFBRUFBQURSTllSUTNkaFJTcm0tNEstYWRwQ0pwWnVGcnREQ05QTTBrNjB1NVl0RElLTjZ5cklUVHJna0Fod3JuQXJBd2NMQXFqczlNQ0RhazRtM0E2cjN3T09YZ1FxaWZlUVFIRC1TQ0JXOVVJdjNabzFnMERXMElvYWRLRWgtQ0R3X01XY2dBQSIsImFtciI6WyJwd2QiLCJtZmEiXSwiYXBwaWQiOiIwNGIwNzc5NS04ZGRiLTQ2MWEtYmJlZS0wMmY5ZTFiZjdiNDYiLCJhcHBpZGFjciI6IjAiLCJlX2V4cCI6MTA4MDAsImZhbWlseV9uYW1lIjoiU2FjaGRldmEiLCJnaXZlbl9uYW1lIjoiTmlrIiwiaW5fY29ycCI6InRydWUiLCJpcGFkZHIiOiI2NS4zNi44OC4xNjYiLCJuYW1lIjoiTmlrIFNhY2hkZXZhIiwib2lkIjoiZTJlM2Q0N2UtNGJjMC00ODVjLTg5MTUtZjIwNWRjNGU4NjlhIiwib25wcmVtX3NpZCI6IlMtMS01LTIxLTEyNDUyNTA5NS03MDgyNTk2MzctMTU0MzExOTAyMS0xMzUwMDI4IiwicGxhdGYiOiI1IiwicHVpZCI6IjEwMDM3RkZFODAxQjZCQTIiLCJzY3AiOiJ1c2VyX2ltcGVyc29uYXRpb24iLCJzdWIiOiI2Z3d4WUFKem4zM3h6WVhfVWM4cHpNcGc4dzk1NVlHYTJ2VnlpazMtVDZ3IiwidGlkIjoiNzJmOTg4YmYtODZmMS00MWFmLTkxYWItMmQ3Y2QwMTFkYjQ3IiwidW5pcXVlX25hbWUiOiJuaWtzYWNAbWljcm9zb2Z0LmNvbSIsInVwbiI6Im5pa3NhY0BtaWNyb3NvZnQuY29tIiwidmVyIjoiMS4wIn0.jEAMzSd4bV0x_hu8cNnQ7fActL6uIm97U7pkwCz79eaSfEnBdqF8hXEJlwQh9GYL0A3r8olNdjr1ugiVH6Y0RFutn7iD8E-etkVI9btE1aseZ3vvZqYeKPhA1VytBsTpb4XO2ZI094VynTeALoxe7bbuEzl5YaeqtbC5EM0PMhPB04o7K1ZF49nGKvA385MHJU3G-_JT3zV-wdQWDj5QKfkEJ0a9AsQ9fM7bxyTdm_m5tQ4a-kp61r92e1SzcpXgCD7TXRHxrZ2wa65rtD8tRmHt6LOi7a4Yx2wPFUpFoeQAcN7p7RKW6t_Cn8eyyvWrrUXximBcTB4rtQTgXCfVUw'

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

Итоговое значение без использования опции --debug будет следующим:
[
  {
    "connectionString": "HostName=youriothub.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=yourkey=,
    "name": "youriothub"
  }
]

Ещё одной полезной операцией, которая доступна в Azure CLI, является output. Она позволяет форматировать конечное значение, используя различные средства синтаксического анализа. Например, применяя ту же команду, что была задействована выше, мы можем поменять формат конечного значения с JSON (по умолчанию) на таблицу.
az iot hub show-connection-string -g yourresourcegroupname -o table"

Конечное значение должно принять вид таблицы:
ConnectionString                                                                                                                        --------------------------------------------------------------------------------------------------------------------------------------  --------------
HostName=youriothub.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=yourkey= 
Name
youriothub

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

Например, приведенные ниже команды используют запрос, чтобы получить данные обо всех IoT Hub, созданных в западном регионе в рамках одной подписки, и затем переформатировать полученный результат в tsv:
az iot hub list --query "[?contains(location,'westus')].{Name:name}" -o tsv

Язык запроса (JMESPath) эффективен при фильтрации запросов, подробнее о нём вы можете прочитать здесь.

На этом пока всё. Следующий пост будет об использовании обозревателя центра IoT Azure для создания устройств и выполнения операций отправки и получения с его помощью.

Над материалом работали ahriman и Schvepsss.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333530/


Метки:  

[Из песочницы] Снимаем “4D видео” с помощью depth-сенсора и триангуляции Делоне

Понедельник, 17 Июля 2017 г. 17:42 + в цитатник

Постквантовая реинкарнация алгоритма Диффи-Хеллмана: вероятное будущее (изогении)

Понедельник, 17 Июля 2017 г. 16:57 + в цитатник

Метки:  

[Из песочницы] Как тысячи игроков Eve Online помогают в расшифровке человеческого тела

Понедельник, 17 Июля 2017 г. 16:38 + в цитатник
От переводчика
Представляю вашему вниманию перевод статьи Мэта Камена (Matt Kamen) от 28 апреля 2016 года.
В статье рассказывается о том, какие возможности могут предоставить и предоставляют многопользовательские игры в решении важных проблем для всего человечества, связанных с необходимостью привлечения большого количества человеческих ресурсов.

image

Credit CCP Games

EVE Online — не просто игра в интернете о космических кораблях и политике в жанре фантастики. С марта (2016 года — прим. переводчика) разработчики CCP Games запустили Проект Открытие (Project Discovery) — инициативу, направленную на улучшение научного понимания человеческого тела на мельчайших уровнях.

Запущенный во взаимосвязи с проектом Атлас Белков Человека (Human Protein Atlas) и платформой Масштабная Многопользовательская Игровая Онлайн Наука (Massively Multiplayer Online Science), проект подключается к самому большому ресурсу игры EVE Online — её базе игроков — чтобы помочь классифицировать миллионы белков. «Мы показываем им изображение, и они могут изменять его цвет, нанося на него зеленые или красные краски, чтобы помочь им немного лучше его анализировать», — говорит Линзи Кэмпбелл (Linzi Campbell), разработчик проекта Discovery. «Затем мы также показываем им примеры — цитоплазма является их любимой! Мы показываем им, какими должны быть изображения каждого из них, и просто предлагаем им выбрать несколько вариантов, которые они идентифицируют внутри изображения. Идентификации перемешиваются каждый раз, поэтому это не так просто, как взять и решить: «хорошо, я просто всегда буду выбирать тот, что справа». Им нужно действительно думать об этом».

image
Credit CCP Games

Проект анализа работает в EVE Online в качестве мини-игры и работает в контексте освоения игры. «У нас есть такая NPC-организация (NPC, Non-Player Character — персонаж, управляемый компьютером, а не игроками — прим. переводчика), называемая Drifters (Дрифтеры) — они похожи на таинственную сущность в Новом Эдеме (New Eden — межпланетное учреждение EVE)», — объясняет Кэмпбелл. «Игроки не знают ужасно многого о Дрифтерах в данный момент, поэтому мы замаскировали это во вселенной как ДНК Дрифтера, которую они анализировали. Я думаю, что это подходит просто идеально. Мы назвали это [исследование, проводимое] Сестрами Ив (Sisters of Eve), и так они анализируют эту ДНК Дрифтера».

Результат был потрясающим. «У нас было удивительное количество классификаций, и мы преодолели наши самые смелые ожидания», — говорит Эмма Лундберг (Emma Lundberg), адъюнкт-профессор проекта Human Protein Atlas. «Сейчас, через шесть недель, у нас уже есть почти восемь миллионов классификаций, и игроки провели 16,2 миллиона минут, играя в мини-игру. Когда мы подсчитали, это оказалось — по шведским меркам — до 163 рабочих лет. Это безумие». «Внутренне, у нас были скромные предположения. Мы сказали, что если мы получим 40 000+ классификаций в день, мы будем счастливы. Если мы получим 100 000 в день, то мы будем в восторге», — добавляет Лундберг. «Но когда это достигло пика первый раз, у нас было 900 000 классификаций за день. Теперь это стабилизировалось, но мы все еще получаем около 200 000 в день, поэтому все были ошарашены. Мы такого никак не ожидали».

В настоящее время игроки EVE просматривают изображения из домена Лундберг, которая является директором субклеточной главы атласа. Игрокам потребовалось всего три недели, чтобы осилить всю рабочую нагрузку, и теперь они выполняют второй прогон для достоверности, без каких-либо признаков снижения интереса. «Одной из проблем, связанных с геймификацией науки, является то, что участие быстро падает, и мы надеялись, что мы сможем предотвратить это, используя существующую игру, дополнив вознаграждениями», — говорит Лундберг. «Я думаю, что самое большое отличие — это то, что это интегрировано в игру».

Сам Атлас Белков Человека расширяется на картирование генома человека, но на гораздо меньшем уровне. «У нас около 20 000 генов, и сейчас мы ещё не доказали существование даже более 70 процентов из них. Таким образом, существует большой разрыв между исследованиями белков и исследованиями ДНК, и на то есть несколько причин», — говорит Лундберг. «ДНК можно увеличить, чтобы ее было легко изучить, но вы не можете увеличить белки. Кроме того, поскольку все клетки имеют одну и ту же ДНК, вы можете [просто] взять образец крови [чтобы увидеть её]. Но белки, выраженные в генах, распределены по телу. Вы должны охватить все тело, и поэтому, с технологической точки зрения, гораздо сложнее изучать белки», — продолжает она. «С моей точки зрения, это интересная часть: белки — это молекулы, которые выполняют функцию, а лекарства действуют путем нацеливания на белки. Поэтому, если вы хотите разработать лучшие лекарства, понять, как устроены люди, или понять [их] биологию, вы должны знать, что делают белки.»

image
Credit CCP Games

«Но мы даже близко не знаем этого, поэтому вот что мы делаем — составляем карту того, где находятся протеины. Если мы знаем, что белок находится в печени, в митохондриях, тогда хорошо — он может быть смоделирован в этих процессах, что даст подсказки исследователям. Исследователи могут сказать: «Хорошо, я изучаю печень — каковы все белки, расположенные в печени?.. Меня интересует энергетический метаболизм. Каковы митохондриальные белки в печени?» — так это могут использовать другие исследователи».

Вскоре усилия игроков будут ощущаться и в более широкой научной области. После проверки их категоризаций и анализов — процесса, связанного с контрольными изображениями, которые известны исследователям как заведомо правильные, и используемого для измерения производительности коллективного разума EVE — их результаты были включены в базу данных HPA (атласа). Все данные общедоступны, а атлас насчитывает около 100 000 пользователей в месяц. В среднем каждый день уже публикуются две рецензируемые научные работы, и когда в декабре будет опубликована следующая версия атласа, то будущие документы будут включать данные игроков EVE. «Остается доказать, что игроки могут предоставлять высококачественные исследовательские данные, поэтому научное сообщество сейчас внимательно следит за нами», — говорит Лундберг. Тем не менее, уже есть основания быть уверенными — игроки получают результаты. «Одним из примеров является то, что существует очень неизвестная биологическая структура, которая имеет только три известных белковых компонента», объясняет Лундберг. «Игроки определили еще 100 кандидатов. Это отличная отправная точка для открытия новой биологии — это потрясающе».

Первый раунд Проекта Открытие был настолько успешным, что Кэмпбелл видит возможности продления, переместив область исследований после завершения проекта Атлас Белков Человека. «Причина, по которой мы выбрали «Сестры Ив», в том, что вполне разумно, что они анализировали бы множество разных вещей», — говорит Кэмпбелл. «Это бонус создания рабочего каркаса для этих целей, что мы можем просто поменять изображения и поставить что-то еще. Нечто подобное мы могли бы сделать с раковыми клетками, или c астро планетами (возможно речь о экзопланетах — прим. переводчика). Если бы мы выбрали вариант с планетами, мы, вероятно, просто позволили бы игрокам со временем определить местоположение неизвестной планеты в Новом Эдеме (New Eden) и назвать ее. Я думаю, что это может быть почти что угодно, если это что-то связанное с биологией или космосом».

Оригинальная статья: How thousands of gamers are helping to decode the human body
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333528/


Метки:  

[Перевод - recovery mode ] SDN с платформой Red Hat OpenStack: интеграция с OpenDaylight

Понедельник, 17 Июля 2017 г. 16:21 + в цитатник
OpenDaylight — проект с открытым исходным кодом под эгидой Linux Foundation, направленный на содействие внедрению и развитию программно-определяемых сетей (SDN) путем создания общей отраслевой платформы. Red Hat — платиновый член-учредитель сообщества OpenDaylight, в деятельности которого участвуют как отдельные специалисты, так и крупные сетевые компании. OpenDaylight стимулирует инновации и разработку самых разных вариантов использования.

image

Начиная с версии Red Hat OpenStack Platform 8, Red Hat включает в поставку специализированную сборку OpenDaylight, разработанную совместно с Red Hat OpenStack и предлагаемую в виде ознакомительной версии. В ней присутствуют тщательно отобранные компоненты, которые должны помочь вам развернуть оптимальное и стабильное решение OpenDaylight в качестве сетевого сервера для вашей среды Red Hat OpenStack Platform. Ключевой проект OpenDaylight, используемый в решении Red Hat, — это NetVirt. NetVirt — приложение виртуализации сети на основе OpenDaylight, состоящее из модульных подсервисов, таких как L2, L3, ACL, NAT, DHCP, IPv6 Control и т. д. В настоящее время это приложение поддерживает OpenStack Neutron API и управляет экземплярами Open vSwitch (OVS) с помощью OpenFlow и OVSDB.

Необходимо подчеркнуть, что ни OpenDaylight, ни NetVirt не заменяет собой OpenStack Neutron. Neutron — это основной сетевой API OpenStack, то есть место, где определяются сетевые абстракции. OpenDaylight использует Neutron API, а не заменяет и не изменяет его. Более того, все коммуникации между OpenDaylight и OpenStack осуществляются только с применением общедоступных и общеизвестных REST API.

image

Также мы рады сообщить, что с выходом версии Red Hat OpenStack Platform 10 наше предложение OpenDaylight обновилось. Это по-прежнему ознакомительная версия, тем не менее решение включает в себя значительные усовершенствования, которые должны облегчить настройку и опробование. В основе решения лежат тщательно спроектированные и протестированные пакеты. Ключевые особенности этого выпуска:

  • Обновленный подключаемый модуль OpenDaylight Neutron для OpenStack (networking-odl), основанный на новом выпуске Newton.
  • Обновленный пакет OpenDaylight, основанный на новом выпуске Boron SR2 и новой службе NetVirt (odl-netvirt-openstack). Этот пакет имеет ярко выраженную модульную архитектуру и расширенный набор функций.
  • Более тесная интеграция с инструментом Red Hat OpenStack Platform Director для оркестровки процесса установки и управления. OpenDaylight может работать совместно с ролью контроллера OpenStack Overcloud или в виде отдельной настраиваемой роли на другом узле.
  • Обновленная сопроводительная документация, которая поможет вам приступить к работе. Мы подготовили Руководство по продукту (англ) и Руководство по установке и настройке (англ), эти материалы включены в пакет документации для Red Hat OpenStack Platform.


NetVirt — единственное приложение OpenDaylight, которое в настоящее время предлагает Red Hat, однако мы активно работаем над расширением платформы, внедряем новые приложения и все больше вариантов использования с учетом отзывов, полученных от наших клиентов, партнеров и специалистов на местах.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333526/


Метки:  

React Native с колокольни Android разработки часть 2

Понедельник, 17 Июля 2017 г. 16:09 + в цитатник
Свою прошлую статью я написал спустя 3 дня, после того, как я вообще начал ковыряться в react native, до этого имея опыт только в нативной разработке под android и iOS. Спустя это время я уже успел поработать над реальным react native проектом. И теперь хочу осветить все очевидные и неочевидные моменты с которыми я столкнулся в момент работы с реальным проектом. Всем заинтересованным под кат.

Инструменты


Еще раз хочу осветить тему рабочих инструментов. React native еще не очень близок к версии, хотя бы, 1.0, чему и причина отсутствия полностью рабочего и заточенного под этот продукт IDE. Хотя, внезапно, я наткнулся на это: Deco IDE. Да, это самая настоящая IDE (только под macOS по понятным причинам), да еще и купленная airbnb. Но не все так радужно как оказалось. Да, тут можно «программировать мышкой» просто перетаскивая компоненты в код. Опять же, есть список компонентов, не нужно каждый раз лезть на оф. сайт, чтобы узнать, а какой компонент еще там есть. Так же можно запустить проект буквально 1 тыком (правда, только iOS, с андроидом всегда проблемы). Но на этом все фишки и кончаются. Тут нету ни быстрых переходов к компонентам по клику с зажатым cmd, нету даже адекватного линтера и автодополнения. По функционалу кодинга — это простой блокнот, который только не закрытый тэг сможет подсветить. Но теперь этим инструментом занята крупная компания, надеюсь на его скорое развитие.

В большинстве видео про react native, а так же в скриншотах различных статей я везде видел VS code. Штука действительно неплохая, спокойно подцепляется eslinter как плагин, можно подцепить flow, есть автокомплиты и даже переходы к компонентам. Есть встроенный git и даже интегрированный терминал. И я бы тоже его использовал, но есть огромный для меня минус — по дефолту каждый открытый файл открывается в одной вкладке, как бы заменяя предыдущий. Чтобы открыть 2 вкладки с разными файлами, нужно начать редактирование в файле, затем открывать другой, который уже и откроется во второй вкладке. Если нужно просто быстро просмотреть 2-3 разных файла, обивку на стуле приходится менять это приносит некий дискомфорт.

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

Работа с камерой, картой и другими сложными вещами


Это, пожалуй, наиболее интересный вопрос для всех. Плохая новость — дефолтных компонентов для камеры и карты нету. Нужно использовать нативный код. Хорошая новость — все уже давно сделано до нас:
Дико крутые карты под авторством airbnb. Использовал лично, все замечательно работает как на iOS, так и на андроид, так же отлично кастомизируется.
Камера уже тоже есть. Хотя, лично не пробовал, небыло необходимости, хотя и любопытно.
В геопозицию, благо, умеет из коробки.
Вообще, уже есть куча рабочих компонентов, нужно просто погуглить. Но можно написать и самому.

Рабочий процесс


У react native есть только 1 проблема — андроид проблемы с андроидом. Уж не знаю, проблемы ли это системы или разработчиков, что клали болт на андроид, но с ним вечно какие-то странные косяки.
Самый странный случай: Date переведенный в строку формата: «YYYY-MM-DD HH:mm:ss» имеет разную длину символов на iOS и android, догадайтесь на какой платформе лишний пробел? Что приводит просто к лютой парное, вот казалось бы, код на чистом js, все работает замечательно на iOS, а на андроиде что-то может пойти не так. Поэтому ВСЕГДА нужно проверят приложение на обеих платформах после ЛЮБОГО изменения кода, никогда не знаешь в какую проблему это может вылиться.

На самом деле подобная проблема была единична для меня, почему-то криво работает Date на андроиде, а вот momentJS прекрасно. Так что сразу используйте последнее. А вот с версткой проблемы другого характера.
Во-первых, андроид вообще не умеет в тени, что указываются в стилях. Для него есть отдельный параметр — 'elevation', но только и всего. Цвет тени, радиус, прозрачность — все это проходит мимо андроида.
Во-вторых, разрешение экранов. У яблофонов просто огромные разрешения, особенно в плюсах, от чего, бывают проблемы, когда выставляешь кнопки с нужными размерами шрифтов, на iOS все смотрится хорошо, на андроиде все слипается — экран маловат будет. Благо, react native дает возможность определить платформу, на которой запустилось приложение, и от этого изменять что-то в коде, например, стили.

Что касается самого процесса разработки, то тут сложно описать то чувство свободы, которое ты обретаешь, после нативной разработки под android. Android SDK дает нам инструменты, предназначенные для чего-то конкретного, отойти от которых никак нельзя. Вот было придумано, что должна быть активити, в которой подцепляется класс к layout, и хоть что ты делай, а активити быть должна, даже сам гугл с этим ничего поделать не может. Вот дали они нам data binding, и вот используя эту библиотеку активити в 99% случаев используется как костыль, просто чтобы подцепить layout и ViewModel, попутно передав Model, хотя мы в layout'е уже явно указали и model и ViewModel. Абсолютно никакой логики в этом случае тут нету, а активити есть. Для передачи информации нужен Intent, а он без проблем может передавать только простые типы, а если хочется передать объект, то все, здравствуй Parcelable.
И таких примеров очень много. В случае с react native есть только… JavaScript и все. Ты сам решаешь как сделать тот или иной элемент. Именно поэтому для навигации можно использовать аж 3 разных библиотеки:

Да и вообще, любая задача может быть решена как угодно (ну, почти). И это самое интересное в реактиве.

Компоненты


Отдельного упоминания заслуживают компоненты. Для ребят с веба, это привычный инструмент, а вот для нас, ребят с мобилок — это просто серебряная пуля.
image
Тут у нас 3 разные кнопки. На самом деле не разные, это один компонент. Понимаете масштаб крутизны компонентов? Тут от слова «совсем» можно забыть про копипасту в верстке. Да, в андроиде есть стили, которые теоретически, должны избавить нас от копипасты. Но ведь они применяются к чистым компонентам. Да, я могу задать стиль button, но что бы сделать кнопку как на картинке выше, одним button в андроиде не обойдешься. Это целый отдельный layout, где будет и TextView и ImageView и у всего этого, а так же у layout будут свои параметры стиля. И все 3 кнопки будут отличаться еще и различным количеством этих компонентов, где-то нету картинок, где-то 2 текста и т.п… Другими словами, сделать все эти 3 кнопки на андроиде не сверстав их 3 раза никак не получится. Ну а как получается это делать на реакте? Тут есть 3 щепотки магии:
  1. Props
  2. Отображение только тех элементов, что существуют
  3. Наложение стилей

Подробнее обо всем.
В андроиде мы сначала создаем компонент в layout'е, затем находим его по ID'шнику в активити и передаем какие-то параметры, например, текст меняем. Это работает, если мы заранее знаем что хотим отобразить. В реактиве мы же указываем какой нам создать компонент с НУЖНЫМИ нами параметрами. В чем соль? В props мы можем передавать ВСЕ ЧТО УГОДНО, без каких либо проблем, начиная от простых типов, заканчивая объектами. Допустим, нам нужна еще 1 кнопка, такая же как по середине, только с другой стрелочкой. В андроиде мы бежим рисовать уже 4-ю кнопку, а тут же мы просто передаем через props другую иконку.

Но бОльшая магия твориться вот тут:
{true && Я существую}
{false && Я НЕ существую} 

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

const text = this.props.text;
{text &&  {text}  

Если мы передали в props параметр text, то компонент его отрисует, а если не передали, то не отрисует, ибо зачем? Стоит еще раз акцентировать внимание на динамическую типизацию. С текстом все хорошо, текст есть — true, текста нету — false, тоже и с объектами. А вот с числами беда, отправите 0 — JS будет думать что это false… Для чисел лучше более явно проверять тип.
Начинает доходить логика? Мы делаем компонент, который учитывает все возможные варианты того, что в нем может находится, оборачивая их в конструкцию, что я представил выше.
И тут может возникнуть другая проблема — слишком большой текст, слишком большая картинка и прочее могут сломать внешний вид компонента. Тут нам на помощь приходит пункт номер 3:


{this.props.text}

Стиль мы определяем как массив стилей. Что это значит? Это значит, что если мы НЕ передали в props свой стиль, то компонент будет в дефолтном, который мы определили заранее. Но что, если мы передадим в кастомный стиль 1 параметр, допустим, отступ сверху? И этот компонент будет иметь дефолтный стиль плюс отступ сверху. Смысл в том, что всегда ПОЛНОСТЬЮ применяется дефолтный стиль, только в нем заменяются лишь те параметры, которые мы передаем в кастомном стиле. Т.е. если мы хотим только изменить цвет текста — не беда, размеры, отступы и прочие радости не слетят. А если нам какой-то параметр в стиле не нужен, мы передаем в кастомном стиле этот параметр со значением null.

Заключение


Еще можно упомянуть про работу с данными через redux, но это отдельная философия, рассчитанная на полноразмерные статьи. Скажу за себя, после нативной разработки я прошел все 5 стадий принятия неизбежного, когда работал с redux. Но потом я втянулся и очень зауважал такой подход.

Самый главный вопрос для кого react native? Да для всех. Делая продукт, нужно держать 2 команды разрабов — для iOS и android. Тут же хватит и одной. Во-первых, это тупо дешевле, нужно в 2 раза меньше людей, а во-вторых, удобно — появился баг, поправил сразу на 2 платформы. И серьезные ребята тоже начали втягиваться. Тут уже не только фейсбук и инстаграмм. Airbnb, walmart, testa, думаю, эти ребята что-то знают)

Да и потом, проект еще даже не близок к релизу версии 1.0, а им уже заинтересованны многие именитые ребята, которые собираются вместе для развития проекта. У нас есть уникальный шанс сесть не на уезжающий поезд, а на проезд, который еще даже не доехал до станции. Все кто овладел этим инструментом (особенно те, у кого есть опыт нативной разработки под мобилки) еще до массового релиза версии 1.0, будут иметь огромное преимущество перед другими.
А вы пробовали писать на react native?

Проголосовало 3 человека. Воздержавшихся нет.

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

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333518/


Paradigm — Дизайн-система Mail.Ru Group, часть 1: Визуальный язык

Понедельник, 17 Июля 2017 г. 15:50 + в цитатник
Несколько лет портальная дизайн-команда Mail.Ru Group занимается обновлением и унификацией продуктов. У нас сформировалась дизайн-система, на которой работают медиа-проекты, мобильный веб и частично productivity-сервисы (постепенно подключаются и другие продукты), сформировался стиль пиктограмм и иллюстраций, стандартизируются промо-письма и промо-сайты. Конечно, ещё не во всех сервисах всё хорошо, а где-то первый редизайн не решил всех проблем, но огромный рывок за прошедшие годы трудно не заметить. Чтобы ускорить процесс обновления и сделать нашу работу публичной, мы открываем наружу часть нашей дизайн-системы Paradigm.

Дизайн-система Mail.Ru Group Paradigm

Предыстория


Мы делали много подходов к «снаряду» — писали спецификации, собирали единый исходник (UI Kit), делали библиотеки элементов и т.п. Но в 2012 году поняли, что это тупиковое направление — дизайн часто «перевирается» на пути из макетов в реализацию, поэтому нужно переосмыслить неэффективную цепочку «гайдлайн -> макет -> вёрстка -> реализация».

Дизайн до унификации

Если «поженить» дизайн и технологии, т.е. перенести дизайн на уровень технической реализации, то получится, что «гайдлайн = макет = вёрстка -> реализация» и мы избавимся от кучи геморроя по внедрению, улучшению и поддержке продуктов. Так началась работа над дизайн-системой в её правильном понимании: единые компоненты на вёрстке, в которые «вшит» дизайн.

Контекст


В нашем подразделении «Почта и портал» около 20 продуктов — productivity (Почта, Облако, Календарь, Mail.Ru для бизнеса), медиапроекты (Авто, Гороскопы, Дети, Добро, Здоровье, Леди, Кино, Медиатор, Недвижимость, Новости, Погода, Спорт, ТВ, Hi-Tech, SEOSan), Beepcar, Ответы, мобильные продукты (myMail, Artisto), главная страница и общепортальные правила для Mail.Ru, поддержка стилистики бренда My.com.

Продукты под брендом Mail.Ru

Требования и контекст здорово отличаются по всей линейке. Например, в медиапроектах важно сочно показать основной контент, а модель потребления новостей достаточно проста. При этом в productivity-сервисах высокая плотность информации и интенсивность взаимодействия с интерфейсом, так что пространства для визуальной экспрессивности меньше — всё уходит на основной контент и инструменты взаимодействия с ним. А есть и вовсе стоящие особняком My.com и Beepcar, которые никак не связаны с брендом Mail.Ru, но они тоже выиграют от использования общих наработок.

Продукты под другими брендами

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

Как сделать дизайн-систему масштабируемой? Наш путь был достаточно извилистым.

В 2012 мы начали переработку мобильного веба — нужно было обновить и запустить с нуля 12 сервисов. Первым делом принялись за гайдлайны и UI Kit, но уже по ходу работы над вторым проектом осознали, что такими темпами далеко не уедем — будем весь год рисовать одни и те же макеты.

Гайдлайны в Confluence

UI Kit для мобильного веба

Вместе с разработчиками пришли к идее распространяемых компонентов, в которые вшит дизайн. Так родился наш первый фреймворк и основа для дизайн-системы, а задачу перерисовки 12 мобильных сайтов мы закончили всего за 2,5 месяца — таких рекордов скорости мы еще не ставили.

Унифицированный мобильный веб




В том же году начался редизайн веб-версий медиапроектов. Первый подход к унификации плохо масштабировался, но в конце 2012 года мы попробовали «бургерный» подход (серия «поясов», «строк», «врезов» или «контейнеров», которые активно используются в современных промо-сайтах). Соединив эту интерфейсную идеологию с созданным для мобильных сайтов фреймворком, в 2014 году мы запустили первые продукты на основе доработанной дизайн-системы. Сейчас их уже 12 и скорость выхода новых версий на рынок стала значительно выше — около полугода от начала проработки до запуска вместо года ранее.

Унифицированные медиапроекты




В 2014 мы провели для одного из продуктов большой хакатон на тему единого визуального языка, который позволил бы объединить не только разные продукты, но и веб, мобильный веб, мобильные и планшетные приложения. Мы и до этого двигались примерно в одну и ту же сторону, но это было скорее общее ощущение, а не понятные принципы. Но именно здесь окончательно сформировалась идея параметрической дизайн-системы, которая за счёт нескольких «слоёв абстракции» (общие параметры -> общие компоненты -> конкретные экраны) стала достаточно гибкой и мощной. Спустя пару месяцев после начала этого процесса анонсировали Material Design, где мы увидели реализацию многих из наших идей на практике — мы двигались в правильную сторону.

Наброски идеологии модульной дизайн-системы

Текущее видение целостной дизайн-системы мы описали в 2015 году и с тех пор постепенно реализуем его.





Текущее состояние


Что такое дизайн-система в нашем понимании?
  • Визуальный язык — определяет то, как мы создаём интерфейсы продуктов. Как и в обычном языке, у нас есть алфавит (переменные), слова (элементы интерфейса), предложения (компоненты) и цельные тексты (экраны и продукты). Алфавит неизменен, словарный запас постепенно меняется со временем, а вот предложения и тексты из них создаются всегда разные.Он показан на design.mail.ru/paradigm.
  • Единые компоненты на технологическом уровне — единственный источник правды. Дизайн «вшит» в них, сервисы получают и обновляют их из единого репозитория. Продукты под брендом Mail.Ru, которые используют их на практике: медиапроекты, мобильный веб, часть productivity-сервисов. Они пока доступны только внутри компании.
  • Шаблоны для дизайнерских инструментов — способ быстро показать идею, просто высокоуровневые скетчи. В идеальной ситуации макеты не верстают, а собирают из единых компонентов. Мы писали о них в начале года.


Живой гайдлайн с компонентами на технологическом уровне (пока не готов к публикации наружу)

Шаблон в Sketch

Ключевые принципы нашей дизайн-системы, которые помогают добиться масштабирования:
  • Модульность — позволяет сравнительно легко управлять большим количеством продуктов. Интерфейс строится по принципу слоёв абстракции: «переменные -> базовые элементы интерфейса -> компоненты для реализации конкретных задач -> экраны продукта».
  • Параметричность — изменение конкретных параметров, из которых строятся элементы интерфейса, позволяет добиться масштабируемости на продукты разных типов. Для этого мы используем переменные и миксины.
  • Минимум костылей — собирай элементы интерфейса из уже существующих переменных, а компоненты — из уже существующих элементов. Любые принимаемые нами решения должны вписываться в систему, жить по её правилам и потенциально быть готовыми к применению на любом из наших продуктов.
  • 4dp — так называемый «супер-пиксель». Краеугольный камень системы, на нём строится вся система размерностей. Мы мыслим исключительно цифрами, кратными 4-м. Со стороны идея делить на 4 даже значения прозрачности покажется ересью, но это значительно сокращает количество споров и расхождений по любым переменным. В шрифтовой части возможны отступления, связанные с рендерингом шрифтов в Windows (размеры 13, 15 и 17), но мы надеемся побороть это со временем.
  • Адаптация под мобильные (малые экраны) и сенсорные экраны (управление пальцем, нет мыши). Любые наши решения априори должны быть touch-friendly — это касается размеров элементов, действий по наведению и т.п. Границы между устройствами размываются и привычные настольные компьютеры имеют сенсорные экраны. Все интерфейсы должны быть либо адаптивными, либо иметь мобильную версию.


Расскажем об этих принципах на конкретных примерах.

Параметричность


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

Сбор кнопки из переменных

Типографика


Все размеры и начертания шрифтов мы храним в переменных, которые используем в нужных ситуациях. Есть несколько больших групп: это заголовки, наборный текст, подписи. Для нашей кнопки мы применим миксин @fontBody, который содержит в себе базовый стиль текста для productivity-сервисов. Это набор из: размера шрифта, начертания, межстрочного расстояния. Если необходимо, указывается цвет и межпараграфное расстояние.

Типографика

Сетка и отступы по 4dp


Каждый элемент дизайн-системы строится по модулям в 4dp (density independent pixels). Это значит, что все размеры элементов интерфейса и отступы между ними должны делиться на четыре без остатка. Это дополнительный «скелет», который вместе с основной сеткой для лейаута экрана даёт гармонию в поведении элементов, плюс накладывает некоторые ограничения в работе. А значит — меньше шансов совершить ошибку. Это удобно также и при работе с мобильными интерфейсами, ведь аналогичная модульная 8-пиксельная сетка используется в Google Material Design.

Для формирования отступов в нашей кнопке мы воспользуемся комбинацией из нескольких переменных: $sizeControlHeight (высота элемента) и $paddingControlButton (внутренних отступов внутри кнопки).

Сетка и отступы по 4dp

Основной цвет и граница


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

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

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

Для нашей кнопки мы зададим стиль обводки, который как раз использует прозрачность 0.12 и толщину линии 1px. Цвет обводки будет смешиваться с основным фоном без необходимости вводить новый цвет; переменная — $colorBorder. Также добавляем кнопке радиус скругления с помощью переменной $sizeBorderRadius.

Граница

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

Для фона кнопки мы задаём основную заливку серым цветом за счёт переменной $colorBgSecondary.

Фон

Затем используем mixin, который будет затемнять нашу кнопку по наведению на 4%.

@mixin stateHover ($colorBgSecondary) { 
background: mix($colorBgSecondary, $colorAccent, 4%); 
}


Состояние наведения

Чтобы получить стиль нажатой кнопки, также применим mixin — он будет затемнять основной фон уже на 8% от стандартного. Нам также нужно увести кнопку в другую плоскость (z-index: -1) — для этого мы убираем тень внизу и добавляем внутри.

@mixin stateActive ($colorBgSecondary) { 
background: mix($colorBgSecondary, $colorAccent, 8%);
box-shadow: $zIndex-1; 
}


Нажатое состояние

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

Положение по z-оси с помощью тени


На z-оси у нас есть четыре положения элементов:
  • элемент ниже базового уровня (например, нажатая кнопка) — вдавлен.
  • элемент на базовом уровне (основной контент: текст, фото и иллюстрации) — лежит на основной плоскости.
  • элемент приподнят над базовым уровнем (кнопки, карточки) — часть лейаута или дополнительная информация к основному контенту.
  • элемент на отдельном уровне (попап, всплывающая подсказка, меню) — способ показать дополнительный контекст без ухода из основного.


Положение по z-оси с помощью тени

В нашей кнопке мы применим параметр $zIndex1.

Положение по z-оси

Что в итоге


normal:
height: $sizeControlHeight; // 32px
padding: 0 $paddingControlButton; // 0 16px
background-color: $colorBgSecondary; // #f0f0f0
border-radius: $sizeBorderRadius; // 2px
border: $sizeBorderWidth solid $colorBorder; // 1px solid rgba(0,0,0,.12)
box-shadow: $zIndex1; // 0 2px 0 0 rgba(0,0,0,.04)
color: $colorBody; // #333333
font-size: $fontBody; // 15px
line-height: $fontBodyLine; // 20px


hover:
@include stateHover ($colorBgSecondary);


active:
@include stateActive ($colorBgSecondary);


disabled:
opacity: .48;


Масштабируемость


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

Например, возьмем простую кнопку, используемую в Почте Mail.Ru:

Простая кнопка в Почте Mail.Ru

Поменяв параметр для фона мы можем легко получить главную кнопку с акцентным цветом Mail.Ru.

Главная кнопка в Почте Mail.Ru

Какие параметры меняем:
background-color: $colorAccent; // #168de2
color: $colorBody; // #ffffff


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

Главная кнопка в Hi-Tech Mail.Ru

Какие параметры меняем:
height: $sizeControlHeight; // 40px
padding: 0 $paddingControlButton; // 0 20px
background-color: $colorAccent; // #5856d6
color: $colorBody; // #333333
border-radius: $sizeBorderRadius; // 4px
font-size: $fontBody; // 17px
line-height: $fontBodyLine; // 24px


Та же самая кнопка после подстановки других переменных на проекте My.com выглядит так:

Главная кнопка в My.com

Какие параметры меняем:
height: $sizeControlHeight; // 40px
padding: 0 $paddingControlButton; // 0 20px
background-color: $colorAccent; // #00abf2
color: $colorBody; // #333333
border-radius: $sizeBorderRadius; // 4px
font-size: $fontBody; // 17px
line-height: $fontBodyLine; // 24px
text-transform: $fontBodyCase // uppercase


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

Главная кнопка в мобильном вебе

Какие параметры меняем:
height: $sizeControlHeight; // 48px
padding: 0 $paddingControlButton; // 0 20px
background-color: $colorAccent; // #168de2
color: $colorBody; // #333333
border-radius: $sizeBorderRadius; // 2px
font-size: $fontBody; // 15px
line-height: $fontBodyLine; // 20px
text-transform: $fontBodyCase // uppercase


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

Paradigm


Начав внедрение дизайн-системы в 2012 году, в 2015 году мы сформировали её целостное видение. Она предполагает единый источник правды, в котором будут чётко прописаны все правила, необходимые для создания интерфейсов. Принципы, рекомендации, конкретные гайдлайны — всё это должно храниться в едином месте и быть на 100% актуальным.

Главным источником правды является живой гайдлайн, который показывает использующиеся на реальных продуктах компоненты. Он декларирует общие правила построения интерфейсов и показывает их на живых примерах. Настоящие живые гайдлайны у нас есть, но довести их до публичного состояния пока не было возможности. При этом описывать гайдлайны скриншотами — тупиковое направление (они моментально устаревают и не имеют даже простейшего взаимодействия), а считать дизайн-системой UI Kit в Sketch или Photoshop — самообман.

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

Визуальный язык

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

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

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

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


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

Будущее


Публикация текущих наработок — приятная веха в развитии дизайн-системы. Но впереди немало работы:
  • Перевести оставшиеся продукты на дизайн-систему.
  • Заменить псевдо-живой гайдлайн на настоящий живой гайдлайн, который выводит использующиеся на продуктах компоненты. Они есть, но пока сыроваты для публикации.
  • Синхронизировать базу элементов интерфейса и компонентов — часть из них есть только в визуальным языке, технологическим фреймворке или дизайнерских шаблонах.
  • Дополнить живой гайдлайн общими принципами взаимодействия, доступности, анимации, voice & tone.
  • Дизайнеры прототипируют на основе реальных элементов и компонентов, чтобы обновлять дизайн-систему и собирать макеты из актуальных частей.


А пока вы можете посмотреть наши текущие наработки. Если у вас идеи, как улучшить их — будем рады вашим советам.

Дизайн-система Mail.Ru Group Paradigm

P.S.


Команда, которая работала над дизайн-системой:
  • Александр Киров — первый UI Kit для мобильных.
  • Антон Епрев — реализация первого прототипа компонентной системы, фреймворк компонентной системы fest.
  • Евгений Беляев — мобильный веб, основа гайдлайна для Android.
  • Дмитрий Осадчук — гайдлайны для комплексного редизайна медиапроектов, ставшие основой системы.
  • Алексей Сергеев — основы гайдлайнов, синхронизация продуктовых линеек.
  • Павел Скрипкин — идеология и основа масштабируемой системы, основы для гайдлайнов Android и iOS, портальная навигация.
  • Геворг Глечян — основа бургерного дизайна, приведение дизайн-системы к масштабируемости.
  • Артём Гладков — основа и развитие для productivity-сервисов, приведение дизайн-системы к масштабируемости.
  • Евгений Долгов — основа бургерного дизайна, визуальный стиль (иллюстрации, иконки, промо-сайты, промо-письма), приведение дизайн-системы к масштабируемости.
  • Андрей Сундиев — идеология и доведение системы до масштабируемости, вёрстка и развитие сайта Paradigm, развитие для productivity-сервисов.
  • Юрий Ветров — идеология и основа масштабируемой системы, основы гайдлайнов по продуктовым линейкам и их синхронизация.
  • Константин Лебедев — фреймворк компонентной системы feast.
  • Константин Зубанов — первое поколение мобильного веба.
  • Мария Боброва — развитие productivity-сервисов.
  • Слава Яшков — основа гайдлайна для iOS.
  • Светлана Соловьёва — новое поколение мобильного веба.
  • Евгений Ферулёв — развитие медиапроектов.
  • Алексей Кандауров — основа для productivity-сервисов, развитие медиапроектов.
  • Разработка медиапроектов и мобильного веба: Александр Бекбулатов, Дмитрий Беляев, Виталий Васин, Павел Вдовцев, Константин Ворожейкин, Евгений Иванов, Андрей Кусимов, Станислав Михальский, Сергей Ножкин, Антон Полещук, Борис Ребров, Павел Рыбин, Максим Трусов, Арстан Торегожин, Павел Щербинин.
  • Разработка productivity-сервисов: Илья Бурлак, Артём Мезин, Станислав Туговиков, Артур Удалов, Егор Утробин.
  • Алексей Судиловский — вёрстка и развитие сайта Paradigm.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333510/


Метки:  

Обновление систем хранения Fujitsu ETERNUS DX начального уровня

Понедельник, 17 Июля 2017 г. 15:48 + в цитатник
В середине мая корпорация Fujitsu представила первые три модели гибридных систем хранения нового поколения из серии ETERNUS DX S4. Предыдущее поколение этих СХД ETERNUS DX S3 было выпущено в 2013 – 2015 годах теперь настало время для обновления линейки, которое началось с моделей младшего класса, предназначенных для малых и средних предприятий. О них сегодня и расскажем.



В отличие от ряда других игроков на рынке СХД, у которых продуктовая линейка представляет собой комбинацию, зачастую не идеально совместимых между собой систем как собственной разработки, продукции OEM-партнеров, так и поглощенных компаний, Fujitsu предлагает заказчикам серию систем младшего, среднего и старшего класса, которая полностью разработана внутри корпорации и использует единую архитектуру и средства управления, а также лицензируется по одной схеме. Многие из функций систем ETERNUS DX уровня high-end поддерживаются и в системах среднего и начального уровня, что позволяет снизить затраты на обслуживание инфраструктуры хранения данных и обучение системных администраторов, например, можно легко мигрировать данные между массивами ETERNUS DX не только разных классов, но и даже разных поколений.

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

Что нового?


По сравнению с аналогичными моделями ETERNUS DX S3 новые гибридные системы обеспечивают двукратное увеличение максимальной емкости, трехкратное увеличение максимального числа обрабатываемых транзакций. Кроме того, в полтора раза выросло число поддерживаемых виртуальных машин и вдвое число поддерживаемых пользователей. Еще одним усовершенствованием дисковых массивов Fujitsu, которое доступно и для владельцев ETERNUS DX S4, стали новые твердотельные диски емкостью 15,36 и 7,68 Тбайт. Относительно недавно Fujitsu начала выпуск полностью твердотельных систем ETERNUS AF, однако, согласно прогнозам аналитиков, в ближайшие годы разница стоимости хранения на флэш-дисках и жестких дисках Nearline SAS сохранится, поэтому, как считают в Fujitsu, спрос на гибридные СХД будет оставаться высоким достаточно долго.

У старшей модели ETERNUS DX200 S4, в которой контролеры построены на шестиядерных процессорах, по результатам независимого тестирования SPC-1 storageperformance.org, производительность превосходит 300 тыс. IOPS при задержках доступа к менее 0,6 миллисекунд. Она способна обслуживать до 2 тыс. виртуальных машин. Эта система расширяется до десяти дисковых полок с 264 дисками общей емкостью 4055 Тбайт и оснащена системной памятью 64 Гбайт. В ней применяется дедупликация и сжатие, существенно снижающие стоимость хранения при использовании твердотельных дисков. В новом релизе микрокода ETERNUS DX, который также можно использовать и в ранее выпущенных системах ETERNUS DX S3, реализован усовершенствованный механизм сжатия данных. Например, можно выбрать из опций «без сжатия», «только компрессия», «только дедупликация» или «компрессия+дедупликация». Механизм сжатия можно отключить в тех случаях, когда дедупликация или компрессия не уменьшает объем данных, но создает лишнюю нагрузку на контроллеры дискового массива (например, при записи мультимедийных файлов и зашифрованной информации).

Также ETERNUS DX200 S4 поддерживает функции:
  • мгновенных снимков Snapshots
  • клонирования
  • синхронной и асинхронной репликации
  • автоматического организации многоуровневого хранения Autotiering с использованием флэш-памяти и жестких дисков, которое существенно уменьшает совокупную стоимость владения
  • динамического выделения емкости Thin Provisioning
  • автоматического управления качеством сервиса (QoS) для предоставления высоких приоритетов обслуживания (например, минимальной величины задержки) бизнес-критичным приложениям

Стоит отметить, что постоянное снижение стоимости твердотельных дисков позволяет с помощью Autotiering построить двухуровневое хранение с помощью жестких дисков Nearline SAS для холодных данных и дисков SSD для горячих данных (при традиционном подходе использовался еще промежуточный уровень из жестких дисков SAS Enterprise 10 тыс. и 15 тыс. оборотов/мин, однако сейчас становится экономически обосновано хранение всех горячих данных на твердотельных накопителях). Если же из-за ограничений бюджета есть возможность приобрести только несколько SSD для своего массива, то в этом случае можно использовать их как кэш для ускорения доступа к данным, хранящимся на жестких дисках.


Архитектура ETERNUS DX

Модель DX100 S4 примерно вдвое уступает по масштабируемости DX200 S4 (она расширяется до 144 дисков и 2212 Тб и оснащена 32 Гбайт системной памяти), но не поддерживает дедупликацию и сжатие. Обе модели ETERNUS DX S4 могут подключаться к сети хранения и хостам по Fibre Channel 8/16 Гбит/с, iSCSI 1/10 Гбит/с, Ethernet 1/10 Гбит/с и SAS 3/6/12 Гбит/с. Они поддерживают пакет программ Eternus Storage Cluster, с помощью которого можно построить отказоустойчивый кластер с доступностью выше шести девяток (99,9999%), т.е. меньше одной минуты простоев за год. В такой кластер на основе Storage Cluster можно объединять две СХД ETERNUS DX разного типа (гибридные и/или полностью твердотельные). Программное обеспечение Storage Cluster реализует зеркалирование критически важных данных между двумя массивами через SAN (на базе Fibre Channel или iSCSI) и, при необходимости, прозрачное для пользователей и приложений восстановление данных в автоматическом или ручном режиме (подробнее об этом решении).

Наконец, младшая модель DX60 S4, рассчитанная на небольшие компании с ограниченным бюджетом, масштабируется до трех полок и 96 дисков емкостью 480 Тбайт и снабжена системной памятью 8 Гбайт. В отличие от более дорогих моделей она не поддерживает функции удаленной репликации, дедупликацию/сжатия, Autotiering и автоматического QoS. Стоит отметить, что новые ETERNUS S4 поддерживают upgrade до более мощной модели заменой контроллеров и без миграции хранящихся на дисках системы данных (data-in-place), что значительно сокращает риски модернизации инфраструктуры хранения и простои бизнес-приложений из-за отсутствия доступа к данных.

Для управления всеми тремя моделями используется пакет программ ETERNUS Storage Foundation (SF) v16, который применяется и для администрирования ETERNUS DX среднего и старшего класса, а также полностью твердотельных ETERNUS AF. В стандартную поставку этих СХД включен пакет Storage Foundation Express, который реализует базовый функционал управления хранением, и ознакомительную 90-дневную версию почти всех возможных лицензий для ETERNUS.

В ближайшее время Fujitsu планирует представить еще несколько моделей гибридных систем хранения из серии ETERNUS DX S4.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333478/


Метки:  

СУБД для 1С Fresh. Быстро. Надежно. Бесплатно

Понедельник, 17 Июля 2017 г. 15:44 + в цитатник
Кнопка уже несколько лет для работы с бухгалтерскими базами использует технологию публикаций 1C Fresh. Мы уже недавно писали о нашем опыте эксплуатации. Использование нами в качестве СУБД PostgreSQL вызвало интерес и ряд вопросов, поэтому мы решили рассказать об этом подробнее.

image


Введение

В самом начале мы использовали в качестве СУБД традиционный для 1С MS SQL Server. Когда наш Fresh дорос до необходимости горизонтального масштабирования, стало понятно, что по экономическим соображениям нужна альтернатива продукту от Microsoft. Тогда мы внимательно посмотрели в сторону PostgreSQL, тем более что специалисты из 1С его рекомендовали к использованию в инсталляции 1С Fresh. Мы провели простое сравнение производительности на стандартных операциях и выяснили, что база Бухгалтерия Предприятия (БП) 3.0, содержащая около 600 областей работает не хуже. В то время мы переходили на схему нескольких виртуальных машин на Linux с сервером приложений и СУБД. Об этом немного рассказано в статье. Но по разным причинам через год пришли к схеме сервер приложений на Windows и СУБД с несколькими информационными базами (ИБ) на Linux. Но смеем вас заверить, что проблем с работой сервера приложений на Linux у нас не было, изменения связаны с некоторыми другими нашими особенностями работы.

Итак, в качестве сервера баз данных был выбран PostgreSQL. В этой статье Кнопка расскажет, как мы подружили одно с другим, и как это всё заработало.

В первой инсталляции использовали готовые deb-пакеты PostgreSQL 8.4.3-3.1C, предоставляемые 1С, так как это была рекомендуемая для использования версия. Но к сожалению, столкнулись с проблемой зависимостей при установке на Debian Wheezy, являющийся на тот момент oldstable выпуском, содержащим пакеты apache2.2 (поддержки apache2.4 в 1С тогда еще не было). В то время мы держали СУБД и сервер приложений на одном хосте, поэтому приходилось использовать oldstable. Для установки этой версии PostgreSQL требовался libc6 из Debian Jessie. В результате такого скрещивания получилась система, с которой особо ничего не сделаешь, даже установка NFS-клиента ломала необходимые для работы зависимости. Но переходить на другой дистрибутив Linux нам было не выгодно стратегически. Когда мы начали активно использовать микросервисы (для простоты мы называем их роботами), которые взаимодействовали с сервером приложений через COM-соединение, в базах данных начали появляться висящие коннекты, которые приводили к утечке памяти. Эта проблема решалась переходом на новую версию PostgreSQL, но в тот момент 1С еще не выпустил дистрибутив этой версии.

Мы приняли волевое решение перейти на использование сборки PostgreSQL 9.6 из репозитория Postgres Professional. Проблемы с зависимостями и утечкой памяти остались позади, и мы начали решать вопросы масштабируемости, распределения нагрузки и увеличения времени доступности. В настоящее время специалистами 1С уже обновлены сборки PostgreSQL, самая свежая 9.6.3, это вполне актуальная версия и надежнее использовать именно её. По информации от 1С новые сборки будут выпускаться оперативно.

В настоящее время мы работаем на Debian Jessie и далее мы будем рассматривать все вопросы в рамках этого дистрибутива.

Состояние нашей системы мы отслеживаем с помощью Zabbix, выглядит это вот так:



На графиках еще присутствуют старые серверы, но продуктив уже переведен с них на PostgreSQL 9.6.

А еще мы меряем количество транзакций:

image

И количество добавленных, измененных и удаленных строк:

image

В эксплуатации СУБД мы внимательно следим за нашими показателями и все настройки, приведенные ниже, родились именно из реальной эксплуатации и наблюдений. У нас сейчас 2 основных сервера СУБД, каждому из которых выделено по 8 ядер и 40 Гб памяти. Диски с базами располагаются на SSD. Этих ресурсов нам хватает для обслуживания 7 ИБ БП 3.0 с включенным режимом разделения данных (200-800 областей в одной базе). При такой конфигурации мы добились неплохой утилизации ресурсов с одной стороны и хорошего запаса для роста и пиковых нагрузок с другой.

Кластеры в PostgreSQL

При размещении нескольких ИБ на одной виртуальной машине, мы столкнулись со сложностью администрирования. Каждая ИБ желала своих настроек сервера, любая остановка СУБД отключала все базы, а еще архивация WAL совсем не имела смысла, потому что восстановление через этот механизм откатывало бы все базы на сервере.

Для начала каждую из наших баз разместили в отдельном кластере PostgreSQL, что дало возможность гибко управлять ими, запускать несколько независимых копий PostgreSQL на одном хосте, настроить потоковую репликацию, архивирование WAL, а также восстановление данных на момент времени (PiTR).

На практике процесс развертывания выглядит так:

У нас имеется машина, с установленным Debian 8 Jessie, уже установлен PostgreSQL 9.6 из репозитория Postgres Professional.

Создадим наш новый кластер:

# pg_createcluster 9.6 -p 5433 -d /databases/db_01


После этого в /databases создастся каталог db_01, в котором разместятся файлы данных, а файлы конфигурации в /etc/postgresql/9.6/db_01/. Кластер будет использовать 9.6 версию PostgreSQL его экземпляр будет запущен на порту 5433. Сейчас кластер не запущен, это можно проверить командой:

# pg_lsclusters


Вносим изменения в конфигурационный файл кластера postgresql.conf, приблизительные значения параметров можно получить используя PgTune. За что отвечает тот или иной параметр подробно рассказано в документации, мы же поясним только те параметры, которые PgTune не учитывает.

max_parallel_workers_per_gather полезно установить значение равное количеству воркеров, которые будут использоваться параллельно для последовательного чтения таблиц. Это ускорит многие операции чтения. Исходите из количества ядер на вашем хосте, превышение этого количества не даст прироста производительности, а наоборот, произойдет деградация.

max_locks_per_transaction по-умолчанию 64, но в ходе работы значение подняли до 300. Параметр назначает количество блокировок объектов, выделяемых на транзакцию. Если будет использоваться слейв-сервер, то это значение на нём должно быть равно или больше чем на мастер-сервере.

Если файловая система не достаточно производительна, разместите pg_xlog на отдельном хранилище.

Для примера конфиг файл одного кластера:

# -----------------------------
# PostgreSQL configuration file
# -----------------------------
#------------------------------------------------------------------------------
# FILE LOCATIONS
#------------------------------------------------------------------------------

data_directory = '/db/disk_database_db_01/db_01' 
hba_file = '/etc/postgresql/9.6/db_01/pg_hba.conf'
ident_file = '/etc/postgresql/9.6/db_01/pg_ident.conf'
external_pid_file = '/var/run/postgresql/9.6-db_01.pid'

#------------------------------------------------------------------------------
# CONNECTIONS AND AUTHENTICATION
#------------------------------------------------------------------------------
listen_addresses = '*' 
port = 5433
max_connections = 100 
unix_socket_directories = '/var/run/postgresql' 
ssl = true 
ssl_cert_file = '/etc/ssl/certs/ssl-cert-snakeoil.pem' 
ssl_key_file = '/etc/ssl/private/ssl-cert-snakeoil.key'

#------------------------------------------------------------------------------
# RESOURCE USAGE (except WAL)
#------------------------------------------------------------------------------

shared_buffers = 1536MB
work_mem = 7864kB
maintenance_work_mem = 384MB 
dynamic_shared_memory_type = posix
shared_preload_libraries = 'online_analyze, plantuner,pg_stat_statements' 


#------------------------------------------------------------------------------
# WRITE AHEAD LOG
#------------------------------------------------------------------------------

wal_level = replica 
wal_buffers = 16MB
max_wal_size = 2GB
min_wal_size = 1GB
checkpoint_completion_target = 0.9

#------------------------------------------------------------------------------
# REPLICATION
#------------------------------------------------------------------------------

max_wal_senders = 2
wal_keep_segments = 32

#------------------------------------------------------------------------------
# QUERY TUNING
#------------------------------------------------------------------------------
effective_cache_size = 4608MB

#------------------------------------------------------------------------------
# RUNTIME STATISTICS
#------------------------------------------------------------------------------

stats_temp_directory = '/var/run/postgresql/9.6-db_01.pg_stat_tmp'

#------------------------------------------------------------------------------
# CLIENT CONNECTION DEFAULTS
#------------------------------------------------------------------------------

datestyle = 'iso, dmy'
timezone = 'localtime'
lc_messages = 'ru_RU.UTF-8' # locale for system error message
 # strings
lc_monetary = 'ru_RU.UTF-8' # locale for monetary formatting
lc_numeric = 'ru_RU.UTF-8' # locale for number formatting
lc_time = 'ru_RU.UTF-8' # locale for time formatting

default_text_search_config = 'pg_catalog.russian'

#------------------------------------------------------------------------------
# LOCK MANAGEMENT
#------------------------------------------------------------------------------

max_locks_per_transaction = 300 # min 10

#------------------------------------------------------------------------------
# VERSION/PLATFORM COMPATIBILITY
#------------------------------------------------------------------------------
escape_string_warning = off
standard_conforming_strings = off


#------------------------------------------------------------------------------
# CUSTOMIZED OPTIONS
#------------------------------------------------------------------------------

online_analyze.threshold = 50
online_analyze.scale_factor = 0.1
online_analyze.enable = on
online_analyze.verbose = off
online_analyze.min_interval = 10000
online_analyze.table_type = 'temporary'
plantuner.fix_empty_table = false


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

# pg_ctlcluster 9.6 db_01 start


Для подключения по нестандартному порту в оснастке администрирования серверов 1С Предприятия в параметрах информационной базы в поле «Сервер баз данных» указать:

hostname port=5433

А еще важно не забывать про регулярное обслуживание базы. VACUUM и ANALYZE очень полезны.

Потоковая репликация

Реализация standby-сервера довольно проста.

Настроим master-сервер
Вносим изменения в файл конфигурации postgresql.conf, не забыв, что конфигурируем наш новый кластер и находится файл в /etc/postgresql/9.6/db_01/

listen_addresses = '*'
wal_level = replica
max_wal_senders = 3
wal_keep_segments = 128


Создадим новую роль replica:

postgres=# CREATE ROLE replica WITH REPLICATION PASSWORD 'MyBestPassword' LOGIN;


И разрешим подключение для slave-сервера, поправив файл pg_hba.conf

# TYPE	DATABASE	USER		ADDRESS		METHOD
host    replication	replica		192.168.0.0/24	md5


После этого потребуется перезапустить кластер:

# pg_ctlcluster 9.6 db_01 restart


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

# pg_ctlcluster 9.6 db_01 stop


В файле postgresql.conf включаем режим standby:
hot_standby = on


Очищаем каталог с файлами данных на слейве /databases/db_01/ и делаем копию текущего состояния мастера на слейв:

# cd /databases/db_01
# rm -Rf /databases/db_01
# su postgres -c "pg_basebackup -h master.domain.local -p 5433 -U replica -D /databases/db_01 -R -P --xlog-method=stream"


Будет создан файл recovery.conf, поправим его по необходимости:

standby_mode = 'on'
primary_conninfo = 'user=replica password=MyBestPassword host=master.domain.local port=5433 sslmode=prefer sslcompression=1 krbsrvname=postgres'


В данном случае мы не делаем failover, который будет автоматически забирать роль мастера. Чтобы реплика начала работать в роли мастера достаточно переименовать файл recovery.conf и перезапустить кластер.

Запускаем слейв кластер:

# pg_ctlcluster 9.6 db_01 start


Проверим, что репликация идет. На мастере появится процесс wal sender, а на слейве wal receiver. Более подробную информацию о репликации можно получить выполнив на мастере:

SELECT *,pg_xlog_location_diff(s.sent_location,s.replay_location) byte_lag FROM pg_stat_replication s;


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

SELECT now()-pg_last_xact_replay_timestamp();


Резервное копирование и архивирование WAL

Первоначально резервирование производилось посредством pg_dump раз в сутки, что в совокупности с внутренним механизмом резервных копий областей в 1C Fresh давало приемлемую схему резервирования. Но иногда случаются ситуации, когда между моментом последнего бэкапа и моментом аварии проделано большое количество работы. Чтобы не потерять эти изменения нам поможет архивирование WAL-файлов.

Для включения архивирования WAL необходимо соблюсти три условия:
Параметр wal_level должен иметь значение replica или выше
Параметр archive_mode = on
В archive_command задана команды оболочки, например:

archive_command = 'test ! -f /wal_backup/db_01/%f && cp %p /wal_backup/db_01/%f'

Таким образом мы копируем архивные сегменты WAL в каталог /wal_backup/db_01/

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

#!/bin/bash
db="db_01"
wal_arch="/wal_backup"
datenow=`date '+%Y-%m-%d %H:%M:%S'`
mkdir /tmp/pg_backup_$db
su postgres -c "/usr/bin/pg_basebackup --port=5433 -D /tmp/pg_backup_$db -Ft -z -Xf -R -P"
test -e ${wal_arch}/$db/base.${datenow}.tar.gz && rm ${wal_arch}/$db/base.${datenow}.tar.gz
cp /tmp/pg_backup_$db/base.tar.gz ${wal_arch}/$db/base.${datenow}.tar.gz


Для того чтобы восстановить резервную копию на определенный период времени (PiTR) останавливаем кластер и удаляем содержимое

# pg_ctlcluster 9.6 db_01 stop
# rm -Rf /databases/db_01


Затем распаковываем базовую копию, проверяем права и правим (либо создаем) файл recovery.conf со следующим содержанием:

restore_command = 'cp /wal_backup/db_01/%f %p'
recovery_target_time = '2017-06-12 21:33:00 MSK'
recovery_target_inclusive = true


Таким образом мы восстановим данные на момент времени 2017-06-12 21:33:00 MSK, а точка останова будет сразу после достижения этого времени.

Заключение

В боевой эксплуатации связка 1С Fresh и PostgreSQL показали себя достойно, конечно не сразу все было гладко, но мы справились. СУБД прекрасно работает под нагрузкой, которую генерируют около сотни пользователей, множество фоновых заданий и еще наши роботы день и ночь загружают и проводят выписки, создают документы из других инструментов, анализируют состояние нескольких тысяч областей.

Картинка про надежность связки 1C Fresh и PostgreSQL:

image

У нас более 350 Гб информационных баз отлично себя чувствуют, растут и развиваются. Чего и вам желаем!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333480/


Метки:  

Поиск сообщений в rss_rss_hh_new
Страницы: 1437 ... 1053 1052 [1051] 1050 1049 ..
.. 1 Календарь