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

Поиск сообщений в 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 ленты.
По всем вопросам о работе данного сервиса обращаться со страницы контактной информации.

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

[Перевод] Как на самом деле работает планировщик Kubernetes?

Понедельник, 14 Августа 2017 г. 09:27 + в цитатник
Прим. перев.: Эта статья написана Julia Evans — инженером международной компании Stripe, специализирующейся на интернет-платежах. Разбираться во внутренностях работы планировщика Kubernetes её побудил периодически возникающий баг с «зависанием» пода, о котором около месяца назад также сообщили специалисты из Rancher Labs (issue 49314). Проблема была решена и позволила поделиться деталями о техническом устройстве одного из базовых механизмов Kubernetes, которые и представлены в этом статье с необходимыми выдержками из соответствующего кода проекта.



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

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

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

Для чего планировщик?


Планировщик Kubernetes отвечает за назначение узлов подам (pods). Суть его работы сводится к следующему:
  • Вы создаёте под.
  • Планировщик замечает, что у нового пода нет назначенного ему узла.
  • Планировщик назначает поду узел.

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

В Kubernetes применяется идея контроллера. Работа контроллера заключается в следующем:
  • посмотреть на состояние системы;
  • заметить, где актуальное состояние не соответствует желаемому (например, «этому поду должен быть назначен узел»);
  • повторить.

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

В общем виде работу планировщика можно представить как такой цикл:
while True:
    pods = get_all_pods()
    for pod in pods:
        if pod.node == nil:
            assignNode(pod)

Если вас не интересуют детали о том, как же работает планировщик в Kubernetes, возможно, на этом читать статью достаточно, т.к. этот цикл заключает в себе вполне корректную модель.

Вот и мне казалось, что планировщик на самом деле работает подобным образом, потому что так работает и контроллер cronjob — единственный компонент Kubernetes, код которого был мною прочитан. Контроллер cronjob перебирает все cron-задания, проверяет, что ни для одного из них не надо ничего делать, ожидает 10 секунд и бесконечно повторяет этот цикл. Очень просто!

Однако работает всё не совсем так


Но на этой неделе мы увеличивали нагрузку на кластер Kubernetes и столкнулись с проблемой.

Иногда под навсегда «застревал» в состоянии Pending (когда узел не назначен на под). При перезагрузке планировщика под выходил из этого состояния (вот тикет).

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

Пришло время обратиться к коду. И вот что мне удалось выяснить — как всегда, возможно, что здесь есть ошибки, т.к. всё довольно сложно, а на изучение ушла только неделя.

Как работает планировщик: беглый осмотр кода


Начнём с scheduler.go. (Объединение всех нужных файлов доступно здесь — для удобства навигации по содержимому.)

Основной цикл планировщика (на момент коммита e4551d50e5) выглядит так:
go wait.Until(sched.scheduleOne, 0, sched.config.StopEverything)

… что означает: «Вечно запускай sched.scheduleOne». А что происходит там?
func (sched *Scheduler) scheduleOne() {
	pod := sched.config.NextPod()
    // do all the scheduler stuff for `pod`
}

Окей, а что делает NextPod()? Откуда растут ноги?
func (f *ConfigFactory) getNextPod() *v1.Pod {
	for {
		pod := cache.Pop(f.podQueue).(*v1.Pod)
		if f.ResponsibleForPod(pod) {
			glog.V(4).Infof("About to try and schedule pod %v", pod.Name)
			return pod
		}
	}
}

Окей, всё достаточно просто! Есть очередь из подов (podQueue), и следующие поды приходят из неё.

Но как поды попадают в эту очередь? Вот соответствующий код:
podInformer.Informer().AddEventHandler(
	cache.FilteringResourceEventHandler{
		Handler: cache.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				if err := c.podQueue.Add(obj); err != nil {
					runtime.HandleError(fmt.Errorf("unable to queue %T: %v", obj, err))
				}
			},

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

Как работает планировщик: простым языком


Теперь, когда мы прошлись по коду, можно подвести итог:
  1. В самом начале каждый под, которому потребуется планировщик, помещается в очередь.
  2. Когда создаются новые поды, они тоже добавляются в очередь.
  3. Планировщик постоянно берёт поды из очереди и осуществляет для них планирование.
  4. Вот и всё!

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

Конечно, в действительности планировщик умнее: если под не попал к планировщику, в общем случае вызывается обработчик ошибки вроде этого:
host, err := sched.config.Algorithm.Schedule(pod, sched.config.NodeLister)
if err != nil {
	glog.V(1).Infof("Failed to schedule pod: %v/%v", pod.Namespace, pod.Name)
	sched.config.Error(pod, err)

Вызов функции sched.config.Error снова добавляет под в очередь, поэтому для него всё-таки будет предпринята повторная попытка обработки.

Подождите. Почему же тогда «застрял» наш под?


Всё очень просто: оказалось, что эта функция Error не всегда вызывалась, когда реально происходила ошибка. Мы сделали патч (патч был опубликован в том же issueприм. перев.), чтобы вызывать её корректно, после чего восстановление стало происходить правильно. Класс!

Почему планировщик спроектирован так?


Думаю, что более надёжная архитектура выглядит следующим образом:
while True:
    pods = get_all_pods()
    for pod in pods:
        if pod.node == nil:
            assignNode(pod)

Так почему же вместо такого подхода мы видим все эти сложности с кэшами, запросами, обратными вызовами? Глядя на историю, приходишь к мнению, что основная причина — в производительности. Примеры — это обновление о масштабируемости в Kubernetes 1.6 и эта публикация CoreOS об улучшении производительности планировщика Kubernetes. В последней говорится о сокращении времени планирования для 30 тысяч подов (на 1 тысяче узлов — прим. перев.) с 2+ часов до менее 10 минут. 2 часа — это довольно долго, а производительность важна!

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

Что на самом деле использует планировщик: informers в Kubernetes


Хочу сказать ещё об одном моменте, который кажется очень важным для архитектуры всех контроллеров Kubernetes. Это идея «информаторов» (informers). К счастью, есть документация, которая находится гуглением «kubernetes informer».

Этот крайне полезный документ называется Writing Controllers и рассказывает о дизайне для тех, кто пишет свой контроллер (вроде планировщика или упомянутого контроллера cronjob). Очень здорово!

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

Итак, информаторы! Вот что говорит документация:

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

Когда контроллер запускается, он создаёт informer (например, pod informer), который отвечает за:
  1. вывод всех подов (в первую очередь);
  2. уведомления об изменениях.

Контроллер cronjob не использует информаторов (работа с ними всё усложняет, а в данном случае, думаю, ещё не стоит вопрос производительности), однако многие другие (большинство?) — используют. В частности, планировщик так делает. Настройку его информаторов можно найти в этом коде.

Повторное помещение в очередь


В той же документации (Writing Controllers) есть и инструкции по тому, как обрабатывать повторное помещение элементов в очередь:
Для надёжного повторного помещения в очередь выносите ошибки на верхний уровень. Для простой реализации с разумным откатом есть workqueue.RateLimitingInterface.

Главная функция контроллера должна возвращать ошибку, когда необходимо повторное помещение в очередь. Когда его нет, используйте utilruntime.HandleError и возвращайте nil. Это значительно упрощает изучение случаев обработки ошибок и гарантирует, что контроллер ничего не потеряет, когда это необходимо.

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

Необходимо «синхронизировать» своих информаторов (не так ли?)


И последняя интересная деталь за время моего расследования.

У informers используется концепция «синхронизации» (sync). Она немного похожа на рестарт программы: вы получаете список всех ресурсов, за которыми наблюдаете, поэтому можете проверить, что всё действительно в порядке. Вот что то же руководство говорит о синхронизации:
Watches и Informers будут «синхронизироваться». Периодически они доставляют вашему методу Update каждый подходящий объект в кластере. Хорошо для случаев, когда может потребоваться выполнить дополнительное действие с объектом, хотя это может быть нужно и не всегда.

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

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

Планировщик Kubernetes не синхронизируется повторно


Итак, после знакомства с концепцией синхронизации… приходишь к выводу, что, похоже, планировщик Kubernetes никогда её не выполняет? В этом коде всё выглядит именно так:
informerFactory := informers.NewSharedInformerFactory(kubecli, 0)
// cache only non-terminal pods
podInformer := factory.NewPodInformer(kubecli, 0)

Эти числа «0» означают «период повторной синхронизации» (resync period), что логично интерпретировать как «ресинхронизация не происходит». Интересно! Почему так сделано? Не имея уверенности на сей счёт и прогуглив «kubernetes scheduler resync», удалось найти pull request #16840 (добавляющий resync для планировщика) с двумя следующими комментариями:
@brendandburns — что здесь планируется исправить? Я действительно против таких маленьких периодов повторной синхронизации, потому что они значительно скажутся на производительности.

Согласен с @wojtek-t. Если resync вообще когда-либо и может решить проблему, это означает, что где-то в коде есть баг, который мы пытаемся спрятать. Не думаю, что resync — правильное решение.

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

Советы по чтению кода


Насколько мне известно, нигде не описана реальная работа планировщика Kubernetes изнутри (как и многие другие вещи!).

Вот пара приёмов, которые помогли мне при чтении нужного кода:
  1. Объедините всё нужное в большой файл. Выше уже написано об этом, но вот действительно: переходить между вызовами функций стало намного проще по сравнению с переключением между файлами, особенно когда ещё не знаешь, как всё полностью организовано.
  2. Имейте несколько конкретных вопросов. В моём случае — «Как обработка ошибок должна работать? Что произойдет, если под не попадёт к планировщику?». Потому что есть много кода о близком… как выбирается конкретный узел, который будет назначен поду, но меня это мало волновало (и я до сих пор не знаю, как это работает).

Работать с Kubernetes довольно-таки здорово!


Kubernetes — по-настоящему сложное программное обеспечение. Даже для того, чтобы получить работающий кластер, потребуется настроить как минимум 6 различных компонентов: api server, scheduler, controller manager, container networking вроде flannel, kube-proxy, kubelet. Поэтому (если вы хотите понимать программное обеспечение, которое запускаете, как и я) необходимо понимать, что все эти компоненты делают, как они взаимодействуют друг с другом и как настроить каждую из их 50 триллионов возможностей для получения того, что требуется.

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

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

P.S. от переводчика: читайте также в нашем блоге:
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335552/


Метки:  

Pygest #15. Релизы, статьи, интересные проекты из мира Python [01 августа 2017 — 14 августа 2017]

Понедельник, 14 Августа 2017 г. 07:46 + в цитатник
image Всем привет! Это уже пятнадцатый выпуск дайджеста на Хабрахабр о новостях из мира Python.

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

А теперь к делу!


Релизы


Python 3.5.4
Python 3.4.7
Django 1.11.4
PyTorch 0.2.0

Статьи


OpenDataScience и Mail.Ru Group проведут открытый курс по машинному обучению

Reverse engineer a Python object
О внутренностях объектов в Python.

Python decorators, the right way: the 4 audiences of programming languages
Интересная заметка о декораторах в Python.

The Hitchhiker’s Guide to Machine Learning in Python
Отличный вводный туториал и подборка материалов по машинному обучению для начинающих.

Clean Architecture in Django
Небольшая заметка о чистой архитектуре в Django-приложениях.

A Minimal Django Application
Туториал для начинающих работать с Django — как создать минимальное приложение на данном фреймворке.

Python __init__.py & modular Imports
О работе импорта модулей в Python.

Using K-Means to analyse hacking attacks
Статья об использовании алгоритма «к-средних» для анализа хакерских атак.

Python bytecode reverse-engineering
Крутая статья о реверс-инжениринге байт-кода Python.

Controlling Python Async Creep
Заметка о контролировании асинхронного выполнения кода в Python.

Demystifying Dynamic Programming
О том, что такое динамическое программирование с примерами на Python от freeCodeCamp.

Detecting fake banknotes using TensorFlow
Статья об использовании машинного обучения и TensorFlow для обнаружения фальшивых денег.

Building a Music Recommender with Deep Learning
Как создать свой сервис для рекомендации музыки?

Интересные проекты


Pygorithm
Библиотека для изучения алгоритмов «на лету»

tinychain
«Карманная» реализация Bitcoin

Aptos
Инструмент для валидации данных на основе JSON-схем

Domain Analyzer
Инструмент для анализа безопасности домена на основе всей доступной информации о нём

sandsifter
Инструмент для поиска скрытых инструкций и багов в процессорах x86

Видео


PyCon Australia 2017
Видео с конференции PyCon Australia 2017

Предыдущий выпуск дайджеста ищете здесь:

Pygest #14. Релизы, статьи, интересные проекты из мира Python [18 июля 2017 — 31 июля 2017]

Спасибо за внимание! Присылайте Ваши предложения для публикации в дайджесте!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335538/


Метки:  

Как распознать scam ICO? Часть II. Зрим

Понедельник, 14 Августа 2017 г. 05:28 + в цитатник
Прежде чем начать, хотелось бы сделать две ремарки:

  1. Мне хорошо известна целевая аудитория Хабра и, возможно, поэтому для неё данный материал будет не просто понятен, но и прост. Но с другой стороны, именно вы, жители одного из самого большого it-сообщества в СНГ, сможете всегда дать своим знакомым или просто встретившимся в Сети людям этот материал, чтобы наконец-то избежать очередного, искусственного пузыря.
  2. Второй аспект заключается в том, что понимание и систематизированное знание — две качественно разные категории, поэтому мне, в рамках развития единой репутационной системы (о ней — как-нибудь в следующий раз), хотелось бы начать структурировать то, что известно.



Scam — это обман

Чтобы понять, что scam явление не новое, нужно лишь добавить к нему точку и com — http://scam.com — выдаст сотни результатов по теме. И это неудивительно: людям свойственно ошибаться, а значит всегда найдутся те, кто превратят их ошибки в бизнес.

И вот об этом поподробней.

Скам — это мошенничество: опять же, простой запрос «scam+history» преподнесет большой список из разного рода сервисов, которые тем или иным образом решили сыграть на доверии, глупости или неосторожности пользователей. Сферы будут самыми разными: от энергетики до банковского сектора. Что касается сферы ICO, несмотря на молодость, существует она с 2013 года, в ней хватает скамов.

Попробуем сначала классифицировать скамы:

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

Во-вторых, по сложности:

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

В-третьих, по субъективной стороне, как говорят юристы:

  • Когда создатели изначально не хотят ничего, кроме сбора средств;
  • Встречаются случаи, когда создатели по тем или иным причинам приходят к скаму уже в результате ICO или работы проекта (пожалуй, один из ярчайших примеров — MtGox, а сегодня таким может стать EOS).

В первом случае мошенники сознательно делают всё, чтобы получить побольше и исчезнуть побыстрее. Во втором возможные потери «вкладчиков» связаны с безволием создателя (режим «всё надоело!»), с ссорой внутри команды (в сети можете найти один из аналогов storj & filecoin на эту тему), с банальной жадностью, которая, как известно, приходит во время еды — получения крипто-активов.

Чтобы оценить любой ICO проект нужно акцентироваться на четырех составляющих (как-то уже писал об этом, но сегодня посмотрим шире):

  1. Team — команда;
  2. Tech — технология;
  3. Theme — концепция;
  4. Token — правовой статус реализуемых крипто-активов.

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

Команду всегда нужно проверять на истинность взаимосвязей, то есть искать не просто профиль в facebook, linkedin, но выходить на людей, которые так или иначе где-то реально засвечены. Дело в том, что в онлайн-среде наверняка должны найтись персоны, которые часто сидят в социальных сетях, имеют устойчивые группы общения и вполне открыто обсуждают свою жизнь. Если таковых нет — это очень странно. Конечно, бывают группы, где люди собираются именно потому, что они интроверты, но если из всего сонма знакомых каждого из команды нет ни одного с развёрнутой историей — это должно вызывать подозрения. Теория 6 рукопожатий в этом смысле работает: не обязательно зацикливаться на самой цифре: главное, чтобы участники были связаны с реальным миром:

  • В первую очередь нужно проверять связи с адвизорами — у них репутация стоит денег и поэтому не нужно лениться писать и звонить, дабы подтвердить/опровергнуть информацию о проекте, где они участвуют.
  • Далее юридическое лицо: регистрация, местонахождение (онлайн-карты вам в подарок); если речь идёт о preICO то можно даже проверить почтовый адрес отправкой приветственного письма на бумаге (по крайне мере, дважды я так делал и чутьё меня не подвело). Ассоциации и другие объединения, где должно состоять данное юридическое лицо. Недавно, например, с командой проверял COSS и из 7 запросов получили 7 ответов, подтверждающих, что данное объединение действительно является участником ряда предпринимательских сообществ (см. пример ниже).
  • Есть ещё один момент, который часто приходится использовать в повседневной практике: поиск по номеру телефона или email. Конечно, найти личный адрес кого-то из команды не всегда просто, а телефон может быть создан под специальный проект. Но вероятность нахождения этих данных не так мала. Скажем, до 1/3 проектов так или иначе подобные данные в конце-концов раскрывали. Зачем это нужно? Дело в том, что всё имеет свойство индексироваться. Поэтому старые аккаунты в социальных сетях, на досках объявлений и во множестве других потаённых уголков Кибервселенной часто могут сказать о человеке больше, чем тысячи букв, написанных во славу.



Технологию оценить очень сложно, если вы не специалист. Правда, однажды мне помог банальный поиск исходника, который совпал со скриптом другого проекта почти на 100%. Хорошо, что Интернет создан именно как коллективный разум: задать вопрос на профильном форуме, сайте вопросов или чате (в телеграм, скажем, таких сейчас хватает) может каждый. Сделайте связку между первым и вторым «Т»: какой-нибудь банальный запрос в slack/telegram разработчикам и команде поддержки проекта, в который хотите вложиться: буквально на днях в чате https://t.me/bitfund появился «коэффициент глухоты» (по фамилии фаундера, который не ответил ни на один вопрос, но об этом ещё будет материал, скажу пока лишь, что в клиентах у него был даже Apple, который просил разработать маркетинговую стратегию). Фидбэк от мошенников и не- мошенников абсолютно разный. Мошенники не отвечают вовсе или отвечают предельно размыто на прямые вопросы. Исключения бывают, безусловно, но это уже иной уровень подготовки. К слову, вот небольшой перечень каналов, где можно задать вопрос:

  1. http://toster.ru: не удивляйтесь, т.к. Хабро-сообщество часто помогает обрисовать рамки;
  2. https://t.me/bitfund — хороший чат со специалистами и инвесторами ICO и оценке блокчейн-проектов в целом
  3. https://t.me/ICO_law — чат не такой большой, как предыдущий, но зато здесь очень много полезных ссылок и материалов для начинающих.

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

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

  • Берём Белую книгу и Дорожную карту. В первой написано: «запуск первой стадии состоится не ранее 3 марта 2018 года», Открываем Roadmap и видим: «завершение первой стадии: апрель 2018 года». Срок реализации стадии — 3 месяца. В этом смысле мне не очень нравится подход ZrCoin: «сроки окончания строительства и запуска первой линии производства намечены на весну 2018 г.». Посмотрим, но пока они выглядят завышенными.
  • А теперь давайте взглянем на развитие концепта: сколько времени прошло от момента его появления на свет до первой реализации или хотя бы описания? А сколько дней, недель, месяцев между этой самой реализацией и ICO? Вот здесь можно найти хороший пример для тренировки подобных навыков https://icotracker.net/project/skyway.
  • И самый главный вопрос: как блокчейн-проект победит, говоря условно, в гонке с классическими it? Скажем, как могут победить SONM & Golem команды, которые занимаются тем же самым, но не первый год? Это вопрос сомнения. А вот для скама вопрос стоит проще и жёстче: а вообще такая реализация есть в классическом бизнесе? Нет? Тогда почему?

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

Токен. Наконец-то, после SEC & MAS, люди стали понимать, что выпускать не ясно что, не понятно для кого — не просто странно, но и опасно. В итоге, если видим, что токены созданы по системе «купи дешевле — продай подороже» и за ними не стоит ничего иного: бонусов, доли участия, обратных выкупов и так далее, то это ещё один повод задуматься над ТЭО (технико-экономическое обоснование) и его адекватностью. Вот ещё несколько нюансов по теме:

  1. Есть ли соглашение о распределении токенов?
  2. Как вообще обозначен токен в разных документах: Дорожной карте, Белой книге, публичной оферте и т.д.?
  3. В этом видео вы найдёте не премер скама, а скорее пункта, который среди прочих, выглядит подозрительно: когда в White Paper написано об обратном выкупе, а документах сугубо юридических — нет. Уловка или недомолвка? Зависит от других направлений, но, как минимум, повод изучить проект подробней
  4. Сколько токенов эмитировано и какова их экономика? Скажем, чтобы поддерживать рост и ликвидность ETH необходим ежедневный оборот в 5 000 000 долларов и более. Если его нет, то идёт падение. В этом смысле EHT инфляционный токен, а btc — дефляционный. Стейблкоины же пока только на этапе становления. Зачем это знать? Затем, что Концепт должен учитывать экономическую сущность токена и исходить в показателях роста. Сегодня это делают далеко не все проекты даже из белого списка — это ещё один повод задуматься о возможности участия в них.

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

В России и странах СНГ в основном приоритет за анализом техническим. Давайте же и мы тоже не будем обходить его стороной.

Скажем, тот же . Здесь можно найти интересную информацию об одном из самых подозрительных среди последних. Кроме ICOtracker, есть и ещё ряд подобных проектов: ICOrating, где есть специальная вкладка с одноимённой закладкой, icostats и ряд других. На Golos Ден Иванов делал подборку по этому поводу — к нему и адресую.

Есть также подход, который по существу представляет собой следующую матрицу:



Данный подход был создан Алексом Контегна (Alex Kontegna). Автор объясняет данную структуру оценки ICO следующим образом: «наша карта делит пространство на матрицу с девятью слотами: в положительных (зелёных) и отрицательных (красных) полях, определенными на разных пересечениях. Хорошее применение этой матрицы — измерение параметра риска вашего портфолио (ICO-токенов), если вы владеете несколькими монетами».

К матрице прилагаются следующие простые правила:

  1. Сравните два актива, в которые хотите вложиться, по «красной зоне»: чем больше сумма денег, уже собранная проектом в отрицательной (красной) зоне, тем выше риск, связанный с обладанием подобными токенами. Принцип таков: сервисы с отрицательной зоной покрытия и без прочных оснований в первую очередь становятся ещё менее стабильными, когда растут.
  2. Следуйте противоположному правилу при сравнении двух активов, которые находятся на положительной территории: чем больше сумма, собранная проектом на положительной территории, тем ниже риск, связанный с владением его tokens.
  3. Наконец, следует избегать инвестирования в ICO с отрицательными характеристиками вообще. Конечно, иногда есть факторы, которые преобладают даже над этим. Например, более ранние проекты, которые могут сделать ICO привлекательным с точки зрения спекуляций.

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

Скажем, регистрация домена. Если проект разрабатывался, то у него должна быть, пусть и небольшая, но история. И поэтому домен, которому от роду 1-3 месяца, даже полгода — выглядит странным (если только нет аффилированного с ним). Всегда импонирует открытость данных даже там, где делать этого не обязательно — вот всё тот же пример из последних наблюдений https://who.is/whois/coss.io. При этом: если компания заявляет некую историю по старым проектам, которые даже уже закрыты, то эти сведения можно проверить:

  1. http://web-arhive.ru/ — смотрим, то, что было до прихода ICO с проектами
  2. каталоги (раньше был DMOZ, сейчас это Яндекс и местные каталоги сайтов)
  3. обратные ссылки: когда удаляется сайт далеко не все удаляют ссылки на него, а таких может быть много: партнёры, новостные сайты, форумы
  4. есть ещё более мелкие детали: даты в sitemap старых сайтов или элементы seo-оптимизации на страницах (мошенники обычно на этом не заморачиваются, поскольку делают проекты на коленке и предельно быстро).

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

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

https://matchpool.co — социальная сеть, завязанная на блокчейне. Случилось с ней следующее (по данным Forbes): «В начале апреля 2017 года его создатели с помощью ICO получили $5,8 миллионов. Но уже через пару дней компанию покинул технический директор, которого заподозрили в незаконном выводе средств». Аналогичные истории случались и в других стартапах.

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

  1. Есть мультиподпись;
  2. Формируется некий стабфонд, который будет использован в каких-то неприятных ситуациях (случай с тем же Satoshi Fond);
  3. Существуют смарт-контракты на возврат сумм при определённых ситуациях (не прохождении нижнего порога ICO, форс-мажор и т.п.). Почитать о примерах можно в книге.

В заключение хотелось бы выделить следующие аспекты:

Прежде, чем рваться в бой, обратите внимание на уже существующие scam’ы — изучите, проанализируйте, сделайте обобщающие выводы:

  1. https://nodio.net/ — 2016 год, Украина; сайт не работает.
  2. https://www.ebitz.org/ — 2016 год, Анонимно; сайт работает номинально.
  3. http://www.tithecoin.com/ — 2016 год, США; сайт работает.
  4. https://ascendancy.io/#/ — 2016, Не выяснено; сайт не работает.

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

Нужно понимать, что ICO — начинающий, а значит высокорискованный бизнес. Тем более в рамках последних заявлений SEC & MAS.

Чтобы найти скам нужны не какие-то сверх-методики, машинное обучение и работа с большими данными (хотя это, безусловно, пригодилось бы каждому), а усердие, внимание к деталям и затраченное пропорционально вложениям время на исследование ICO-проектов. Нет времени тратить силы на это? Или не заходите вообще в проекты, или обратитесь хотя бы к тому же https://www.kickico.com/ru/ — ребята, по крайне мере, стараются.

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

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

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

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

  • По критерию восприятия: положительно или отрицательно;
  • По уровню восприятия: сложно или просто;
  • По бальной шкале:
    Десятибалльная — одна из самых простых и понятных: всё, что ниже нуля — ближе к скаму; всё, что выше — дальше от скама;
    Стобалльная. Если в вашем личном наборе оценок сто и более элементов: подход хорош для полуавтоматической оценки;
    Также можно использовать смешанную систему: скажем отрицательным факторам присваивать до 10 баллов в минус, а положительным, соответственно, в плюс. Каждый проект изначально берём за 100% и далее начинаем разбор: если итоговая оценка ниже 33-66%, то это подозрение на скам, 66-75% — норма, далее уже хорошие и отличные проекты.
  • По иным критериям, например, используя систему оценку ценных бумаг или же применяя подход эмоциональной окраски (негативно, нейтрально-негативно, нейтрально, нейтрально-положительно, положительно).

Таким образом, систему выявления скамов можно выстроить, но единственное, что всегда остаётся за скобками — это наша общечеловеческая жадность: если она свойственна вам в критичные моменты, то моя лично позиция проста: «ICO не для вас».

В завершении — небольшая подборка для расширения понимания темы:

  1. Книга об ICO. Часть 1.
  2. Книга об ICO. Часть 2.
  3. Общие вопросы ICO
  4. ICO и легализация средств
  5. ICO: основные риски
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335548/


Метки:  

PHP-Дайджест № 114 – свежие новости, материалы и инструменты (1 – 14 августа 2017)

Понедельник, 14 Августа 2017 г. 02:21 + в цитатник


Свежая подборка со ссылками на новости и материалы. В выпуске: PHP 7.2.0 Beta 2, об истории и безопасности unserialize(), старт PSR HTTP Client, StackOverflow Driven Development, видео с конференций и митапов, и многое другое.
Приятного чтения!



Новости и релизы


  • PHP 7.2.0 Beta 2 — Список новых возможностей ветки 7.2 тут, а протестировать можно из подготовленного Docker-образа. Третий и последний бета-релиз запланирован на 17 августа.
  • Composer 1.5.0
  • PHP 7.0.22
  • PHP 7.1.8
  • [PSR] HTTP Client — Согласно принятому процессу, новые предложения для PSR должны пройти входное голосование, прежде чем будет разработан черновик. Такое голосование прошло для стандарта HTTP Client, а значит в ближайшем будущем группа начнет работу над документом.


Инструменты


  • mihaeu/dephpend — Инструмент статического анализа, который поможет выявить проблемы в архитектуре.
  • spatie/phpunit-watcher — Инструмент для автоматического запуска тестов когда изменен код. Пост в поддержку.
  • Imangazaliev/DiDOM — Простая и быстрая библиотека для парсинга HTML.
  • hirak/prestissimo — Плагин Composer для параллельной установки пакетов. Значительно ускоряет установку зависимостей. Прислал chilic.
  • clue/php-commander — Инструмент для создания простых консольных удобным с интерфейсом.
  • thephpleague/json-reference — Библиотека для работы с JSON-ссылками.
  • paragonie/easydb — Простая и лаконичная обертка над PDO.
  • hjr3/php-rpm — Менеджер процессов для PHP на Rust.


Материалы для обучения




Аудио и видеоматериалы




Занимательное



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

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

Прислать ссылку
Быстрый поиск по всем дайджестам
<- Предыдущий выпуск: PHP-Дайджест № 113

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

https://habrahabr.ru/post/335546/


Метки:  

Немного про ашибки в программном обеспечении и помощь теории конечного автомата

Воскресенье, 13 Августа 2017 г. 22:16 + в цитатник

Работая в сфере ИТ, волей-неволей замечаешь огромное количество ошибок в различном программном обеспечении. Будь то ошибки мировых вендоров Microsoft, или же в прикладных бизнес-решениях фирмы 1С, или же в хваленных Apple с детской фатальной ошибкой "1 января 1970". Что уж говорить про небольшие компании с небольшим штатом программистов?


Насколько ошибки в ПО являются естественным процессом? Давайте разберёмся. Всё ниже является исключительно авторским мнением, в том числе классификация, возможность применения теории конечного автомата, наблюдения. 



Не так давно Samsung заявил о запуске сервиса Samsung Pay,  а наличие у меня часов Samsung Gear 3 открывало мне новое баловство — оплачивать покупки прикосновением часов к терминалу. Не знаю какие трудности произошли при производстве продукта, но первые версии программы мне не позволяли произвести настройку. Лишь с выпуском нескольких релизов я смог использовать сервис.



Все производители делают ошибки в области программного обеспечения, какими бы они крупными и сертифицированными не были.


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


Сколько полегло исследователей в попытке пройти сложные маршруты: Г. Седов, Р. Скотт, В. Беринг... О чём это я?


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



 Ошибки и Теория конечного автомата


Давайте обратимся к теории конечного автомата. В своё время в институте приходилось применять данную методику как в программировании контроллеров, так и в построении систем управления.

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

Представим стандартный граф конечного автомата производственного предприятия с состояниями:
  • Расчет
  • К производству
  • В производстве
  • Готово
  • Завершён



События конечного автомата:
  • a — устанавливается менеджером после подтверждения покупателем;
  • b — устанавливается начальником производства, оценив производственные мощности и возможность выполнения;
  • c — устанавливается работником склада в момент поступления на склад;
  • d — устанавливается менеджером при поступлении денег и передачи груза;
  • e — устанавливается менеджером вручную.

 

Описан тривиальный процесс. В конкурентной борьбе необходимо применять все современные возможности и, конечно, отправка смс заказчику была бы неплохим плюсом, а, возможно, уже и обязанностью. А как вы помните, изначальная задача — автоматизировать процесс. Например, грузчик принимает с помощью сканера штрихкода выпускаемый товар, а система шлёт sms покупателю: «Готово, приезжайте».

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

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



 

Чем функциональнее ПО, тем больше ошибок. Тестировщик помогает, но не всегда — он не знаком с предметной областью так, как проектировщик.

Я для себя определил, что построение графа статусов на базе теории конечного автомата позволяет объемно взглянуть на решаемую задачу.

Помню, ко мне обратился Финансовый директор с просьбой разработать систему депремирования сотрудников. Учет поручений всех сотрудников вёлся в 1С: Документооборот (ДО), учёт рабочего времени в 1С: Управление производственным предприятием (УПП). Если сотрудник просрочил важную задачу, то его лишали премии на Х%. Для этого сверяем время завершения задачи в ДО, получаем данные сотрудника по табелю за период из УПП и определяем место запятой в «казнить нельзя помиловать».

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



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

Процедура тестирования программного обеспечения давно отлажена и стандартизирована. Но массовые продукты всё равно постоянно выпускают релизы с исправлением ошибок. Примеры:
  • WordPress


  • 1С: Комплексная автоматизация 2



Можно ли выпустить Функциональное ПО без ошибок? Нет, таких случаев не наблюдалось.

Связь экономики и технических знаний в области ошибок


Можно ли минимизировать ошибки? Однозначно. Их количество нелинейно снижается соответственно затраченному времени на их поиск и устранение. Время означает затраты. Существует 2 причины поекращения поиска ошибок — потеря экономического эффекта на дальнейший поиск и потеря технических знаний на их устранение.



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

Например, стоит задача разработать программное обеспечение для бортового компьютера нового самолёта. Учитывая колоссальное количество параметров и функций в физике полёта нельзя допустить остановку отладки ПО из-за потери финансирования. Результат будет печальный.

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

При всём при этом останутся «ошибки-ниндзя», которые скроются от всех тестов и обнаружатся лишь пользователями.

Вес ошибок


Вес каждой ошибки разный. В целом, я делю их на 4 вида.

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

Например, я скачал активно продвигаемую программу в Google Play Маркет. Сразу при запуске произошла ошибка.



 

Важная непреодолимая ошибка.

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

Я проложил маршрут в г. Подольск. На одном участке навигатор проложил очень странный маршрут (пробки он не объезжает, ремонта и перекрытия дороги нет). Эта ошибка не критична и я могу продолжать использовать программу, но внести изменения нет.



 

Важная преодолимая ошибка.

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

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



В программе 1С выводилась такая ошибка расчета себестоимости. Пользователь мог (естественно, путём экспериментов) её устранить — перепровести документы. В заявленных возможностях метода РАУЗ это не надо делать, но не на практике.

Замечания.

Это всё остальное. Например, приходит мне сообщение от Добродела, а ссылка неработающая. Сразу видно что тестирование не проводилось.



 

Анализ своих ошибок в качестве резюме


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

https://habrahabr.ru/post/335544/


[Из песочницы] Расчет приоритета комбинаций в техасском холдеме (покере) на PHP

Воскресенье, 13 Августа 2017 г. 20:52 + в цитатник
В этой статье я расскажу про мой способ расчета приоритета комбинаций в техасском холдеме (покере с 2 карманными картами и 5 общими). Условно разделю статью на 6 частей: Создание массива карт, Расчет Стрита, Расчет Флеша и Стрит Флеша, Расчет Парных комбинаций, Окончательный расчет, Вывод на экран. Код пишу в процедурном стиле.

Цель: получить на выходе программы удобочитаемый результат, доступный для дебаггинга и отладки еще на стадии написания кода. Для достижения поставленной цели делаю разницу между комбинациями в 1e+2 (100) раз.

Примерный вид того, что должно получиться в итоге, где 2 последние карты считаю карманными, а первые 5 общими:


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


В колоде 4 масти и 13 достоинств, поэтому массив из 7 чисел буду формировать в диапазоне [2 — 14, 102 — 114, 202 — 214, 302 — 314], а далее оперировать остатками от деления на 100 (%100) этих чисел. Можно, конечно, формировать массив из чисел в диапазоне [2 — 14, 22 — 34, 42 — 54, 62 — 74], а затем сравнивать остатками от деления на 20 (%20). Но удобочитаемость первого варианта по-моему на лицо, поэтому остановлюсь на нем.

function cardsCreation()
{
    $arrayCards = [];
    for ($i = 0; $i < 7; $i++) {
        $card = mt_rand(2, 14); // создаю случайное число в диапозоне от 2 до 14
        $multiplier = mt_rand(0, 3); //формирую случайным образом множитель
        if (1 == $multiplier) { //если множитель равен 1, добавляю к числу 100
            $card = $card + 100;
        } else if (2 == $multiplier) { //если множитель равен 2, добавляю к числу 200
            $card = $card + 200;
        } else if (3 == $multiplier) { //если множитель равен 3, добавляю к числу 300
            $card = $card + 300;
        }

        if (!in_array($card, $arrayCards)) { //проверяю, есть ли в массиве такое число, если нет добавляю его в массив
            $arrayCards = array_merge($arrayCards, [$card]);
        } else { // если число есть в массиве, откатываю цикл, чтобы сформировать новое число
            $i--;
        }
    }
    return $arrayCards;
}

Определение и расчет комбинации Стрит


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

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

Суть моего метода определения стрита сводится к тому, что после сортировки я буду проверять сначала первые пять карт на стрит, затем вторые и третьи. Также не забываю что туз, двойка, тройка, четверка и пятерка тоже составляю стрит. Поэтому, если в наборе есть туз (значение 14), к массиву добавляю восьмой элемент — 1. И следовательно в этом случае нужно проверить четвертую пятерку карт.

function straight(array $arrayCards) {
    $newArrayCards = [];
    $ace = false;
    foreach ($arrayCards as $arrayCard) {
        $newArrayCards = array_merge($newArrayCards, [$arrayCard % 100]);  //создаю массив с остатками от деления на 100
        if(14 == $arrayCard % 100) { //проверка на туз для комбинации А, 2, 3, 4, 5
            $ace = true;
        }

    }
    if($ace == true) {
        $newArrayCards = array_merge($newArrayCards, [1]); //если в массиве присутствует туз, добавляю к массиву 1
    }
    rsort($newArrayCards); //сортирую массив с числами в порядке убывания

    $count = 0; //счетчик, к которому добавляется 1 в случае, если разница между текущим элементом цикла и предыдущим = 1
    $length = 4; //число, показывает до какого элемента массива проверять
    $result = 0; //окончательный результат
    $begin = 0; //число показывает, с какого элемента массива проверять
    for($i = 1; $i <= $length; $i++) {
        if (-1 == ($newArrayCards[$i] - $newArrayCards[$i - 1])) {
            $count++;
        }
        if($length == $i) {
            if(4 == $count) { //$count == 4, когда стрит
                $result = $newArrayCards[$begin] * 1e+8;
            }
            else if($length < 6 or (6 == $length and $ace == true)) {//если стрита нет, идем еще на один круг
                $length++; //увеличиваем число, до которого будем проверять
                $begin++; //увеличиваем число, с которого будем проверять
                $i = $begin; //при попадании в for к $i автоматически добавится 1 ($i++ в for)
                $count = 0; //обнуляю счетчик
            }
        }
    }
    return $result;
}

Определение и расчет комбинаций Флеш и Стрит Флеш


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

При расчете стрит флеша, как и при расчете стрита, можно учитывать только старшую карту комбинации.

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

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

Если флеш не образует стрит флеш, отсортирую остатки от деления на 100 (%100) исходного массива. Далее умножу первые пять членов полученного массива на 1е+10, 1е+8, 1е+6, 1е+4, 1е+2 соответственно.

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

Функция для определения Флеша:

function pokerFlush(array $arrayCards) {
    $suit1 = []; //первая масть
    $suit2 = []; //вторая масть
    $suit3 = []; //третья масть
    $suit4 = []; //четвертая масть
    foreach ($arrayCards as $arrayCard) { //создаю 4 массива, содержащих разные масти исходного массива
        if($arrayCard >= 2 and $arrayCard <= 14) {
            $suit1 = array_merge($suit1, [$arrayCard]);
        } else if($arrayCard >= 102 and $arrayCard <= 114) {
            $suit2 = array_merge($suit2, [$arrayCard]);
        } else if($arrayCard >= 202 and $arrayCard <= 214) {
            $suit3 = array_merge($suit3, [$arrayCard]);
        } else {
            $suit4 = array_merge($suit4, [$arrayCard]);
        }}
    if(count($suit1) >= 5) {  //если количество карт первой масти больше или равно 5
        $result = straightFlush($suit1); //проверяю не образует ли данная комбинация стрит флеш
        if(0 == $result) {//если стрит флеша нет
            foreach ($suit1 as $key1 => $s1) {//выбираю остатки от деления на 100
                $suit1[$key1] = $s1 % 100;
            }
            rsort($suit1); //сортирую массив по убыванию
            $result = $suit1[0] * 1e+10 + $suit1[1] * 1e+8 + $suit1[2] * 1e+6 + $suit1[3] * 1e+4 + $suit1[4] * 1e+2;
        }
    } else if (count($suit2) >= 5) {   //если количество карт второй масти больше или равно 5
        $result = straightFlush($suit2);
        if(0 == $result) {
            foreach ($suit2 as $key2 => $s2) {
                $suit2[$key2] = $s2 % 100;
            }
            rsort($suit2);
            $result = $suit2[0] * 1e+10 + $suit2[1] * 1e+8 + $suit2[2] * 1e+6 + $suit2[3] * 1e+4 + $suit2[4] * 1e+2;
        }
    } else if (count($suit3) >= 5) { //если количество карт третьей масти больше или равно 5
        $result = straightFlush($suit3);
        if(0 == $result) {
            foreach ($suit3 as $key3 => $s3) {
                $suit3[$key3] = $s3 % 100;
            }
            rsort($suit3);
            $result = $suit3[0] * 1e+10 + $suit3[1] * 1e+8 + $suit3[2] * 1e+6 + $suit3[3] * 1e+4 + $suit3[4] * 1e+2;
        }
    } else if (count($suit4) >= 5) {     //если количество карт четвертой масти больше или равно 5
        $result = straightFlush($suit4);
        if(0 == $result) {
            foreach ($suit4 as $key4 => $s4) {
                $suit4[$key4] = $s4 % 100;
            }
            rsort($suit4);
            $result = $suit4[0] * 1e+10 + $suit4[1] * 1e+8 + $suit4[2] * 1e+6 + $suit4[3] * 1e+4 + $suit4[4] * 1e+2;
        }
    } else {
        $result = 0;
    }
    return $result;
}

Функция для определения Стрит Флеша (аналогична Стриту, только нужно учесть, что количество элементов массива может быть не только 7, но еще и 5, и 6, и что возвращаемый результат этой функции должен быть больше):

function straightFlush(array $arrayCards) {
    $newArrayCards = [];
    $ace = false;
    foreach ($arrayCards as $arrayCard) {
        $newArrayCards = array_merge($newArrayCards, [$arrayCard % 100]);  
        if (14 == $arrayCard % 100) {
            $ace = true;
        }
    }
    if ($ace == true) {
        $newArrayCards = array_merge($newArrayCards, [1]);
    }
    rsort($newArrayCards); 
    $count = 0; 
    $length = 4; 
    $result = 0; 
    $begin = 0; 
    for ($i = 1; $i <= $length; $i++) {
        if (-1 == ($newArrayCards[$i] - $newArrayCards[$i - 1])) {
            $count++;
        }
        if ($length == $i) {
            if (4 == $count) { 
                $result = $newArrayCards[$begin] * 1e+16;
            } else if ((7 == count($arrayCards) and ($length < 6 or (6 == $length and $ace == true))) or
                (6 == count($arrayCards) and ($length < 5 or (5 == $length and $ace == true))) or //если число элементов исходного массива = 6
                (5 == count($arrayCards) and (5 == $length and $ace == true))) { //если число элементов исходного массива = 5
                $length++; 
                $begin++; 
                $i = $begin;
                $count = 0;
            }
        }
    }
    return $result;
}

Определение и расчет парных комбинаций


Существует пять парных комбинаций: каре (4 карты одного достоинства), фулл хаус (3 карты одного достоинства и 2 карты другого достоинства), тройка (3 карты одного достоинства), две пары (2 карты одного достоинства и 2 карты другого достоинства), пара (2 карты одного достоинства).

Важно при расчете помнить, что в комбинации фулл хаус главным является сочетание из трех карт, а из двух второстепенным, т.е., например, комбинацию из 3-х двоек и 2-х десяток будем считать, как 3*1e+12 + 10*1e+10, а не по достоинству карт.

А также при расчете парных комбинаций нужно учитывать проблемы:

1. То, что более 5 карт образуют комбинацию.
2. То, что у нас может возникнуть ситуация, при которой комбинаций более одной.

Для подсчета совпадения карт буду использовать три счетчика, которые будут считать парные карты в колоде. Там, где счетчик равен 1 — участвуют 2 карты в комбинации, где счетчик 2 — 3 карты, где 3 — 4 карты.

Рассмотрим все возможные варианты сочетания счетчиков:

100 — пара
110 — 2 пары
111 — 3 пары (нужно преобразовать к виду 110 (две пары))
200 — тройка
210 — фулл хаус
120 — фулл хаус (нужно преобразовать к виду 210 (фулл хаус))
211 (121, 112) — фулл хаус + пара (нужно преобразовать к виду 210 (фулл хаус))
220 — 2 тройки или фулл хаус + 1 карта (нужно преобразовать к виду 210 (фулл хаус))
300 — каре
310 (130) — каре + пара (нужно преобразовать к виду 300 (каре))
320 (230) — каре + тройка (нужно преобразовать к виду 300 (каре))
Далее произведу окончательный расчет парных комбинаций.

function couple(array  $arrayCards) {
    $newArrayCards = [];
    foreach ($arrayCards as $arrayCard) {
        $newArrayCards = array_merge($newArrayCards, [$arrayCard % 100]); //создаю массив с остатками от деления на 100
    }
    rsort($newArrayCards); //сортирую массив с числами в порядке убывания

    $count1 = 0; //счетчик для первой пары
    $count2 = 0; //счетчик для второй пары
    $count3 = 0; //счетчик для третьей пары

    $match1 = 0; //сюда положу значение первой пары
    $match2 = 0; //сюда положу значение второй пары
    $match3 = 0; //сюда положу значение третьей пары


    for($i = 1; $i < count($newArrayCards); $i++) {

        if ($newArrayCards[$i] == $match1 or $match1 == 0) { //первое парное сочетание
            if ($newArrayCards[$i] == $newArrayCards[$i - 1]) {
                $match1 = $newArrayCards[$i];
                $count1++;
            }
        } else if ($newArrayCards[$i] == $match2 or $match2 == 0) { //второе парное сочетание
            if ($newArrayCards[$i] == $newArrayCards[$i - 1]) {
                $match2 = $newArrayCards[$i];
                $count2++;
            }
        } else if ($newArrayCards[$i] == $match3 or $match3 == 0) { //третье парное сочетание
            if ($newArrayCards[$i] == $newArrayCards[$i - 1]) {
                $match3 = $newArrayCards[$i];
                $count3++;
            }
        }
    }

    //здесь я преобразую 111 к 110 (2 пары) и 211 к 210 (фулл хаус)
    if(($count1 == 1 or $count1 == 2) and $count2 == 1 and $count3 == 1) {
        $count3 = 0;
    }
    //здесь я преобразую 121 сначала к 211 для простоты вычислений, а затем к 210 (фулл хаус)
    else if($count2 == 2 and $count1 == 1 and $count3 == 1) {
        $support = $match2;
        $match2 = $match1;
        $match1 = $support;
        $count1 = 2;
        $count2 = 1;
        $count3 = 0;
    }
    //здесь я преобразую 112 сначала к 211 для простоты вычислений, а затем к 210 (фулл хаус)
    else if($count3 == 2 and $count1 == 1 and $count2 == 1) {
        $support = $match3;
        $match2 = $match1;
        $match1 = $support;
        $count1 = 2;
        $count3 = 0;
    }
    //здесь я преобразую 220 к 210 (фулл хаус)
    else if($count1 == 2 and $count2 == 2 and $count3 == 0) {
        $count2 = 1;
    }
    //здесь я преобразую 120 к 210 (фулл хаус)
    else if ($count1 == 1 and $count2 == 2 and $count3 == 0) {
        $support = $match1;
        $match1 = $match2;
        $match2 = $support;
        $count1 = 2;
        $count2 = 1;
    }
    //320 к 300 и 310 к 300
    else if($count1 == 3 and ($count2 == 2 or $count2 == 1)) {
        $count2 = 0;
    }
    //230 к 320 и затем к 300 и 130 к 310 и затем к 300
    else if($count2 == 3 and($count1 == 2 or $count1 == 1)) {
        $support = $match2;
        $match2 = $match1;
        $match1 = $support;
        $count1 = 3;
        $count2 = 0;
    }

    //каре
    if ($count1 == 3) {
        $count1 = 1e+14;
    }
    //фулл хаус
    else if ($count1 == 2 and $count2 == 1) {
        $count1 = 1e+12;
        $count2 = 1e+10;
    }
    //тройка
    else if ($count1 == 2 and $count2 == 0) {
        $count1 = 1e+6;
    }
    //2 пары
    else if ($count1 == 1 and $count2 == 1) {
        $count1 = 1e+4;
        $count2 = 1e+2;
    }
    //пара
    else if ($count1 == 1 and $count2 == 0) {
        $count1 = 1e+2;
    }

    $result = $match1 * $count1 + $match2 * $count2;// $match1 и $match2 будут равны 0, если совпадений не было
    return $result;
}

Окончательный расчет


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

Расчет старшей карты:

1. Определю наибольшую и наименьшие по приоритетности карманные карты. Для этого сравню их остатками от деления на 100 (%100).
2. К наибольшей по приоритетности карте добавлю наименьшую по приоритетности деленную на 100.

function priority(array  $arrayCards) {
    //здесь я определяю старшую карту
    if($arrayCards[5] % 100 > $arrayCards[6] % 100) { //условились, что две последние карты массива - карманные
        $highCard1 = $arrayCards[5] % 100;
        $highCard2 = $arrayCards[6] % 100;
    } else {
        $highCard1 = $arrayCards[6] % 100;
        $highCard2 = $arrayCards[5] % 100;
    }


    $flush = pokerFlush($arrayCards); //вызываю функцию для расчета флеша
    $straight = straight($arrayCards); //вызываю функцию для расчета стрита
    $couple = couple($arrayCards); //вызываю функцию для расчета пар

    //далее определяю результат согласно приоритету комбинаций
    if($flush >= 1e+16) {
        $result = $flush; //стрит флеш
    } else if($couple >= 1e+14 and $couple < 1e+16) {
        $result = $couple; //каре
    } else if($couple >= 1e+12 and $couple < 1e+14) {
        $result = $couple; //фулл хаус
    } else if($flush >= 1e+10) {
        $result = $flush; //флеш
    } else if($straight >= 1e+8 and $straight < 1e+10) {
        $result = $straight; //стрит
    } else if($couple >= 1e+6 and $couple < 1e+8) {
        $result = $couple; //тройка
    } else if($couple >= 1e+4 and $couple < 1e+6) {
        $result = $couple; //две пары
    } else if($couple >= 1e+2 and $couple < 1e+4) {
        $result = $couple; //пара
    } else {
        $result = $highCard1 + $highCard2 * 1e-2; //старшая карта
    }
    return $result;
}

О выводе на экран


Выводила я результат в браузер, используя вот такой спрайт (брала картинку с сайта: fondhristianin.ru/?p=2941), как background-image для div.



Ширину и высоту для div задавала равными размеру одной карты, т.е. если размер изображения 572px*328px (как в данном случае), а в ширину количество карт равно 13, в высоту — 5, ширину и высоту задавала 44px*65.6px. Далее меняла background-position с учетом ранее сформированного массива карта.

Расчет background-position для любого из divов по оси х:

100/12 * ($arrayCards[$i] % 100 - 2)

где $arrayCards — ранее сформированный массив.
$i — порядковый номер карты.

Пояснения к расчету:
В ряду 13 карт, начало 1-ой карты — 0%, начало 13-ой карты — 100%, поэтому разница позиций — 100% / 12 (а не 13). Приводим числа карт из вида [2-14, 102-114, 202-214, 302-314] к [0-12]. Для этого возьмет остаток от числа карты и отнимем от остатка 2. Умножим полученное число на разницу позиций.

Расчет background-position для любого из divов по оси y:

100/4 * floor($arrayCards[$i] / 100)

Пояснение к расчету:
В ряду 5 карт, начало 1-ой карты — 0%, начало 5-ой карты — 100%, поэтому разница позиций — 100% / 4 (а не 5). Приводим числа карт из вида [2-14, 102-114, 202-214, 302-314] к [0-3]. Для этого разделим число карты на 100 и округлим в меньшую сторону (можно использовать и простую операцию округления, она сработает аналогичным образом). Умножим полученное число на разницу позиций.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335540/


Метки:  

TSP problem. Mixed algorithm

Воскресенье, 13 Августа 2017 г. 18:42 + в цитатник

Метки:  

Итак, вы решили развернуть OpenStack

Воскресенье, 13 Августа 2017 г. 18:30 + в цитатник

Вы наверняка слышали об OpenStack. Блин, да о нем говорят на каждом более-менее связанном мероприятии. Все кому не лень пропагандируют OpenStack. Модно, молодежно, все уже есть, Open Source, вливайся давай. И вот наслушавшись тонны маркетингового булшита, вы решаетесь: Будем ставить OpenStack!

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

Предыстория


Об OpenStack я узнал на одной из конференций по OSS году примерно в 2012-м. В то время я работал в компании активно использующей большие кластера (100+ машин), однако без виртуализации, оркестрирования (kickstarter + IBM CSM в счет?) и в основном с пакетным исполнением задач: запустил, отработало, забрал результат. Полноценного понимания что такое облака и зачем они нужны еще не было, но интерес возник. Конечно сразу же возникло желание развернуть новую крутую штуку, которая вот прям сейчас сделает все хорошо.

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

В общем, в 2012-м мы развернули OpenStack, на тот момент это был Essex, запустили проект, прожили с такой облачной инфраструктурой до 2014-го года, кажется до релиза Grizzly включительно. Сил и желания поддерживать его дальше не было, и OpenStack был с позором выпилен.

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

Итак, приступим, что же мне не нравится в Openstack и весьма вероятно не понравится вам.

Он чересчур комплексный


Даже не так. Он, *****, МОНСТРУОЗНЫЙ. Нет, взгляните сами.



Когда-то давно, когда мы ставили Essex, там было все относительно просто и понятно. Keystone (служба авторизации), Glance (служба хранилища образов) и Nova (служба управления гипервизорами). Кроме того там еще был Horizon (дашборд) и куча мелких и не очень зависимостей. Каждый узел системы обрастает чуть ли не десятками вспомогательных демонов. На controller node через некоторое время становится страшно смотреть.



Так, когда наш виртуальный кластер приблизился к 20 серверам, controller node стал безбожно тормозить, по непонятной причине. Ну точнее понятной, но мне непонятно, зачем identity service грузила процессор на 100%?

Из комплексности происходит следующий недостаток.

Он запутанный


Архитектура OpenStack достаточно сильно фрагментирована. Есть очень большое количество «движущихся частей», взаимосвязь который между собой не всегда абсолютно ясна. У вас что-то сломалось? Окей, попробуй понять где это что-то сломалось и почему. OpenStack Foundation похоже гордится, что в OpenStack более 20 миллионов строк кода, даже на главную своего сайта вынесли. Так вот, ЭТО НИФИГА НЕ ДОСТОИНСТВО.

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

Если вам надо залезть под капот, чтобы понять что там происходит…
image

Дело в том, что являясь OSS, OpenStack пытается быть kind of unix-way. Т.е. под капотом все эти монструозные службы на самом деле дергают десятки и сотни unix-утилит по собственной логике, которую вам придется изучить и возможно даже дебажить. С документацией, по крайней мере раньше было, все плохо. Зачем вам рассказывать какие именно правила iptables мы добавляем на хост и для чего? У нас же суперкрутое приложение которое делает все само и не требует вашего вмешательства. Хотите добавить свои правила? Нуу, удачи, исходники-то открыты.

Пока вы более-менее вписываетесь в сценарий, предполагаемый авторами — все более-менее окей. Если же вам понадобилось сделать шаг в сторону, ждите трудностей. Запасайтесь man'ами, терпением, возможно вам придется изучить еще несколько несвязанных напрямую с задачей проблем, например как работает RabbitMQ и что ему еще надо?

Из этого проистекает следующая проблема.

Он ненадежный


Казалось бы логично, чем сложнее система, тем менее она надежна. Но видимо эта истина не для всех. Готовьтесь искать источник подземных стуков, запускать демоны в ПРАВИЛЬНОЙ последовательности, много гуглить и читать логи, копаться в исходниках и вот это все.

Некоторые решения на мой взгляд просто спорные. Служба метаданных на виртуальном IP-адресе эмулируемом через iptables? Серьезно? Очень «надежная» работа dnsmasq по выдаче IP виртуалкам. Тысячи их.

И это усугубляется тем что.

Он становится еще больше


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

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

  • Identity service (keystone)
  • Image service (glance)
  • Compute service (nova)
  • Networking service (neutron)
  • Dashboard (horizon)
  • Block Storage service (cinder)
  • Bare Metal service (ironic)
  • Container Infrastructure Management service (magnum)
  • Database service (trove)
  • DNS service (designate)
  • Key Manager service (barbican)
  • Messaging service (zaqar)
  • Object Storage services (swift)
  • Orchestration service (heat)
  • Shared File Systems service (manila)
  • Telemetry Alarming services (aodh)
  • Telemetry Data Collection service (ceilometer)


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

Например, во времена Essex не было простого способа добавить запись о вашей новой виртуалке в ваш DNS-сервис. Руками — пожалуйста. Хуки? Не, не слышали. Я рождения designate так и не дождался.

А еще знаете что?

Он ломается


От релиза к релизу. Т.е. ну вот вы наконец-то запилили инфраструктуру своей мечты, все худо-бедно работает как рассчитывали, но не хватает одной мааааленькой детали. А в новом релизе она есть. Ну по крайней мере по Release Notes.

Окей гугл, давай обновим наш OpenStack. И тут выясняется, что функционал, который вы с радостью использовали — выпилили. Ну потому что. Ну некрасивый он был и вообще, мы лучше сделаем, честно-честно. В следующем релизе. Может быть. А пока вот вам попроще, но ведь работает же! Ну и плевать что не в вашем случае, но работает!

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

А в следующем релизе ребята из OpenStack решили что баста, мы выпилим функционал работы с сетью в отдельный модуль (будущий neutron), реализуем что-нибудь простое вроде один роутер на виртуальную сеть ну и играйтесь пока. Т.е. нужно было бы пустить весь трафик целого кластера через единичный узел нашей сети, он бы и стал бутылочным горлышком.

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

Он сырой (местами)


А еще очень дивное чувство испытываешь, когда тебе нужен функционал, ну, скажем, деление на зоны. Ну вот есть у тебя машины с большими винтами, есть с SSD, есть с видюхами, хочу разбить кластер на зоны, чтобы виртуалка падала на ту машину, у которой необходимый ресурс есть. Ну ок, читаем доку, вроде бы availability zones подходит. Настраиваем, включаем. И ничего. В доке написано что все должно, а на практике ничего. Лезем в код, а там.



Будет реализовано. В следующем релизе. Может быть. Ну ты понял. Смотри предыдущий пункт.



Есть ли плюсы, какие будут выводы?


Лично для меня вывод простой. Ванильную версию OpenStack лучше не использовать. Я не знаю как обстоят дела с вендорскими версиями и у всяких контор, торгующих инсталляциями «под ключ», но как по мне это несколько противоречит самой идеологии «свободного облака». Мы опять получаем vendor lock-in, только под другим соусом.

Хотите попытать счастье с ванильным OpenStack? Нет, ну в целом пожалуйста. Плагинов много, комьюнити большое, маркетингового булшита вообще выше крыши. Удачи, в общем. Но для небольших и средних инсталляций я бы скорее не советовал.

На мой взгляд одна из главных проблем OpenStack проистекает из не совсем верного архитектурного посыла. Стремясь сделать просто для конечного пользователя, они сделали по итогу слишком сложно. Любой допил под свои нужды превращается в кошмар, потому что даже такой простой и банальной вещи как хуки на события не завезли. А как бы это упростило реализацию многих вещей…

В общем после полутора лет борьбы с OpenStack мы от него отказались и перешли на другое облако. Управление инфраструктурой стало простым и приятным, а обновлять версий также просто как apt dist-upgrade.

Что это за облако и почему оно удобнее OpenStack я постараюсь рассказать в следующей статье. (СПОЙЛЕР: это OpenNebula).
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335530/


Метки:  

5 популярных мифов о дизайне логотипов

Воскресенье, 13 Августа 2017 г. 18:26 + в цитатник
image

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

Миф первый: Логотип должен показывать сферу деятельности



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

Посмотрите вокруг: как часто вы видите на логотипе автопроизводителя машину?
А куртку на логотипе изготовителя курток? Тем не менее, Mitsubishi — это машины, Starbucks — кофе, а Apple —  смартфоны.

Чаще всего ваш логотип увидят по запросу «поесть», «купить машину» или «подстричься». Лого — это способ быть узнаваемым, а не ответ на вопрос «чем вы занимаетесь?».

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

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

Миф второй: Ценность логотипа в затраченных усилиях


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

image

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

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

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

Логотип без фирменного стиля — бесполезен. Если вы знаете где будет использоваться лого, видите идеальный образ компании и ее аудиторию, тогда стоит обратиться к профессиональному дизайнеру и заказать у него не только логотип
но и весь фирменный стиль компании. А если вы не поняли о чем речь —
к профессиональному дизайнеру стоит обратиться тем более. Когда есть стиль,
то логотип перестает быть “галочкой”, вокруг него организована целая концепция и поэтому он приносит объективную пользу.

Миф третий: В логотипе должен быть скрытый смысл



image

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

С другой стороны, логотипов в которых нет никакого скрытого смысла намного больше. Причина — отсутствие практической пользы.
В среднем, у человека есть около секунды чтобы заметить логотип, при этом детали он почти не запоминает. В апреле Логомашина провела небольшой эксперимент , в рамках которого прохожие по памяти рисовали логотипы известных компаний — Lacoste, Apple, Yota, Peugeot, Qiwi, Мегафон и других.
Опыт показал что люди помнят только общие черты известных лого, иногда затрудняясь даже с формой и цветом.

Не смотря на это, снова увидев логотип на вывеске человек сразу же узнает его и идентифицирует с компанией. В этом смысл дизайна. Влияет ли на этот процесс скрытый смысл заложенный в логотипе? Не думаю. Стрелочка FedEx, улыбка Amazon или рукопожатие клиента и производителя на логотипе Hyundai стали известны только после того, как стала известна сама компания. Никто не сможет точно сказать
помогла ли им вложенная в логотип идея.

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

Миф четвертый: Похожие логотипы — это плохо



image

Конечно, если ваш логотип — копия с лого конкурента, это плохо. Клиенты будут путаться.

Но ударяться в оригинальность ради оригинальности — ничуть не лучше. У вас может быть настолько оригинальный логотип, что вас просто не поймут. Клиент обратится к вашим, более спокойным, конкурентам.

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

Поиск «плагиата” действительно интересен, но на эффективности логотипов Puma и Jaguar, CNN и SEGA, Promt и Google Drive, Land Rover и Ford, Gucci и Chanel — это никак не сказывается. Вы никогда не спутаете эти компании. То, что цель дизайнера делать каждый логотип абсолютно непохожим на другие — это стереотип. Буква «A» похожа на букву «A». и с этим ничего не поделаешь. Тоже самое касается всех графических решений и большинство логотипов отличаются друг от друга только деталями.

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

Миф пятый: Логотип — это очень важно



Конечно, логотип важен, но его значимость часто переоценивают. Логотип не загипнотизирует клиентов, не важно, насколько крутое агентство его сделало и сколько ваших коллег сказали: «Классный лого!».

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

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

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

Одна картинка с лого, какой бы прекрасной она не была, не принесет результата.
Знак будет успешным, если правильно его использовать. Он должен размещаться на вывесках, форме сотрудников, продукции и других носителях оформленных в соответствии с фирменным стилем компании. В случае успеха —  логотип прекрасный способ поселиться в умах и сделать свой символ “именем нарицательным”. Миллионы покупают китайские футболки в интернет-магазинах, просто потому на них изображен зеленый крокодил Lacoste или “вжух” от Nike.

Вывод



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

Мы также сделали видеоверсию этой статьи, посмотреть можно здесь:





Текст: Николай Романов
Видео: Данила Баранов, Роман Горбачёв
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335536/


Метки:  

Дайджест интересных материалов для мобильного разработчика #216 (6 августа — 13 августа)

Воскресенье, 13 Августа 2017 г. 16:28 + в цитатник
В центре этой недели – история противостояния разработчиков, ДИТа Москвы и закрытие API для доступа к электронным дневникам. А кроме нее: автоматизация тестирования, чистая архитектура, мобильный фрод и многое другое.



Сначала они воруют, а когда ты побеждаешь, то тебя убивают

В начале лета 2017 года, я спросил ЕМП: «Будут ли какие-то изменения в методах или в функционале?», а мне ответили, что пока они не знают. 1 августа я получил письмо о том, что АПИ больше не будет и попросили меня сообщить моим пользователям, что теперь надо пользоваться госуслугами.

Заблуждения Clean Architecture

На первый взгляд, Clean Architecture – довольно простой набор рекомендаций к построению приложений. Но и я, и многие мои коллеги, сильные разработчики, осознали эту архитектуру не сразу. А в последнее время в чатах и интернете я вижу всё больше ошибочных представлений, связанных с ней. Этой статьёй я хочу помочь сообществу лучше понять Clean Architecture и избавиться от распространенных заблуждений.

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

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

Дайджест доступен и в виде рассылки. Подписаться вы можете тут.

iOS


Android


Windows


Разработка


Аналитика, маркетинг и монетизация


Устройства, IoT, AI



< Предыдущий дайджест. Если у вас есть другие интересные материалы или вы нашли ошибку — пришлите, пожалуйста, в почту.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335534/


Optimization Unity3d UI by GPU (for example minimap) или создаем миникарту без дополнительных камер и спрайтов

Воскресенье, 13 Августа 2017 г. 15:55 + в цитатник
Всем привет.

«Если можешь что-то посчитать на GPU, делай это»
// Конечно в рамках разумного

image
VS
image
Обращаем внимание на разницу в фпс.
Начну пожалуй с предыстории. Один из наших программистов, решил проверить UI на предмет падения фпс. И мы нашли интересную зависимость, при отключении миникарты фпс поднимался в процентном соотношении. Интересно. Нужно решать проблему. Сразу напишу что про атласы и различные пулы, мы пробывали. И тогда я решил занятся этим вопросом более детально. И тут первая мысль, которая меня посетила, UI использует материал, значит можно все перенести на ГПУ, начнем.

Начал гуглить, находил много скажем так, нехороших решений, например таких как
Не делайте так, даже если хотите сделать быстро
Почему выше пример плохо, можно найти в комментариях. Но для ленивых я перечислю.
streeter12 4 июля 2016 в 14:51
Данный метод несмотря на свою простоту имеет явные недостатки.
1. Низкая производительность.
2. Для добавления новых меток надо создавать новые сферы (лишний хлам в префабах).
3. Добавление новых типов меток и их фильтров для различных игроков сильно затруднено.
4. Для смены внешнего вида метки необходимо создавать меш!
5. Лишние объекты на каждой сцене => лишняя сложность => сложнее разработка и поддержка.
6. Сложно тестировать => больше возможных багов (с учетом 3).

7. Реалтаймовая замена типа.
8. Нужно захломлять сцену фейковой подложкой.
9. Как быть с теми кто не должен учитывать вращение? обнулять в Update или таскать через tranform.position.
и т.д.

Нечего не найдя, в итоге начал писать шейдер.
С чего я начал.
1. Нужно как то хранить сами иконки. Атлас подойдет. Теперь нужно найти подходящий для тестов. Взял из игры WOW. там он уже был правильного содержания.

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

В общем, начнем реализацию.


static const int MaxCount = 256;
float4 _Targets[MaxCount];
float _WorldSizeX;
float _WorldSizeY;


Такие поля я объявил в шейдере. Поставил максимально 256 на мапе точек. Остальные будут отбрасываться. float _WorldSizeX поле решило проблему с преобразованиями, я как есть решил кормить Vector3 в шейдер. Не хитрыми махинациями, я получил индексы и нормализованные координаты, и тем самым получил практически то что хотел.
Нюанс: GC считает y иначе снизу в врех. Я конечно сделал обратные значения, чтобы левая верхняя была индексом 0. Но потом решил отказаться от этой затеи. Лучше решать это путем верхнего слоя. Например кодом.

И того у меня были заняты 3 поля из Vector4 (X Z W) чем я занял Y будет позже.

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

Для примера как примерно выглядит скрипт для шейдера.
protected virtual void Update ()
{
for (int i = 0; i < list.Length; i++)
{
list[i] = new Vector4(0, 0, 0, -1);
}

for (int i = 0; i < list.Length && i < targets.Count ; i++)
{
list[i] = new Vector4(targets[i].x *k.x, targets[i].y, targets[i].z*k.y, targets[i].w);
}
image.GetModifiedMaterial(image.material).SetVectorArray("_Targets", list);
}


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

image

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

Тот самый свободный Y, я решил использовать в качестве угла. С ним пришлось отдельно повозится, причина была выше, а именно инверсия координаты Y. Именно из-за вращения я решил использовать все как есть.
fixed a = _Targets[i].y;
fixed resultX = tX;
fixed resultY = tY;
if (a != 0)
{
fixed x0 = minX + (sizeX * 0.5);
fixed y0 = minY + (sizeY * 0.5);
resultX = x0 + (tX - x0) * cos(a) - (tY - y0) * sin(a);
resultY = y0 + (tY - y0) * cos(a) + (tX - x0) * sin(a);
}


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

Выводы

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

Выложу тестовые коды и результаты профайлера.
Заполнение спрайтами.
protected virtual void Start ()
{
tests = new List();
float x = 10;
float y = 10;

for (int i = 0; i < 256; i++)
{
int idx = Random.Range(0, prefabs.Count);

GameObject obj = Instantiate(prefabs[idx].gameObject);
RectTransform t = obj.GetComponent();
t.SetParent(parent);
t.localPosition = new Vector3(startPosition.x + x, startPosition.y + y, 0);
if (useRotation)
{
t.rotation = Quaternion.Euler(0, 0, Random.Range(0, 360));
}
x += step;
if (i % 20 == 0)
{
y += step;
x = 0;
}
tests.Add(t);
}
}

Заполнения через прокси класс для шейдера
item.type = Random.Range(0, 64); означает тип иконки
void Start () {
tests = new List();
float x = 10;
float z = 10;

for (int i = 0; i < 256; i++)
{
Item2 item = new Item2();
item.position = new Vector3(x, 0, z);
if (useRotation)
{
item.rotation = Random.Range(0, 360);
}
item.type = Random.Range(0, 64);
x += step;
if (i % 20 == 0)
{
z += step;
x = 0;
}
tests.Add(item);

}
}


Профайлер для шейдера (на сцене еще 3 куба)
image
Профайлер для спрайтов (на сцене еще 3 image в качестве префабов)
image

и напоследок пример с маской.
image

P.S.
"Если можешь что-то посчитать на GPU, делай это"
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335524/


Метки:  

Мастер, победивший смерть… через Power Point. Рецензия на книгу А. Каптерева «Мастерство презентации»

Воскресенье, 13 Августа 2017 г. 15:33 + в цитатник


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

Несмотря на то, что презентации есть в школьных программах, их делают почти по всем предметам (во всех вузах страны), хорошая студенческая презентация оказывается на вес золота. Мои попытки улучшить ситуацию не всегда были успешными — в образовательной программе по иностранному языку нет отдельного времени, чтобы разобрать эту важную, но непростую тему. Поэтому снова и снова я погибал от текста, набранного Comic Sans 12 размера на кислотно-зеленом слайде. Снова и снова следил, как зачитывается этот текст и затем по спирали вылетает клипартовый человечек.

Эту проблему описал Алексей Каптерев в знаменитой презентации «Смерть через Power Point (и как от нее спасаться)». Я впервые увидел её на английском языке, и она мне очень понравилась. Как и нескольким миллионам пользователей Slideshare. Затем меня заинтересовал человек, создавший этот хит.

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

Общее впечатление

Оригинальное название работы «Presentation Secrets. Do What You Never Thought Possible with Your Presentations» — дословно «Секреты презентации. Делай с помощью своих презентаций то, что всегда считал невозможным». (Героическое, амбициозное и по-американски нескромное название, как мне кажется). Как видим, перевод русскоязычного вариант немного изменен, но сохранен этот «замах» на глобальность. Соглашусь с автором, так как тоже считаю, что умение донести мысль помогает сделать невозможное и решить самые большие проблемы. Исторических примеров этого множество.

Плюсы



1. Книга легко читается потому, что напоминает разговор или, скорее, диалог-презентацию. Алексей Каптерев ставит вопросы и отвечает на них, предлагает задания для выполнения, шутит. Поэтому 330 страниц книги прочитываются как-то быстро.

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

3. В тексте отлично сочетаются теория и практика. Работа посвящена, в первую очередь, практическим навыкам и конкретным «рабочим» инструментам. Но для доказательства их эффективности автор использует научные факты и результаты современных исследований. Поэтому все сформулированные правила и принципы убедительны.

Минусы



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

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

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

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



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

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

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

Структура книги



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

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

Как рассказывать истории (глава про сторителлинг)

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

Цели автор выстраивает по степени важности:
  • цель минимум — чтобы люди вас услышали,
  • следующая цель — запомнили,
  • далее — действия (пошли и сделали то, что вы им сказали)
  • и цель максимум — стали лучше, изменились, победили проблему, как вы им показали.


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



История — скелет презентации — должна взывать к эмоциям слушателей, «зацеплять за живое». Для этого в истории должен быть конфликт (принцип контраста).

Есть 4 типа конфликтов в сторителлинге:
  • С самим собой (у героя есть неразрешенные внутренние проблемы, которые выражаются внешне),
  • С другим человеком / компанией (сравнение ценностей или достижений, демонстрация преимуществ своего героя),
  • С господствующей парадигмой (герой-аутсайдер, бросающий вызов настолько крупному конкуренту или нерушимому стереотипы, миф о Давиде и Голиафе),
  • С внешними силами (природы, судьбы, возможностей человека, экономикой и другими силами, которые должны иметь какое-то внешнее выражение, не быть абстрактными).


Рассказать историю помогают сравнения, которые подчиняются принципам:
  • Узнаваемость (сравнивать что-то новое с известным, например, новый макбук эйр помещается в обычном конверте для документов).
  • Рождение эмоций (смерть, секс, политика, религия).
  • Могут быть очевидными (без куртки «Джимми две куртки» будет обычным Джимми).
  • Избегание непредсказуемых ассоциаций при сравнении (например, религиозные темы могут рождать самые разные ассоциации, нужно избегать негативных).




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

Автор предлагает 5 способов организации информации для лучшего усвоения:
  • объединяющий метафорический образ,
  • алфавит (акронимы, буквы списка составляют слово),
  • последовательность событий,
  • иерархия,
  • категории (какой-то объединяющий признак).


Что нужно для хорошего дизайна слайдов (вторая глава)

В дизайне слайдов автор придерживается идей Г. Рейнольдса (дзен презентации), Эдварда Тафти (дизайн — это не «украшательство», а смысл), Дж. Желязны и других признанных «классиков жанра».

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



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

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

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

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

И третий принцип — единства — в том, что все лишнее нужно безжалостно удалить со слайдов. Замысловатый, загруженный слайд будет «съедает» драгоценное внимание зрителей и время презентации.



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

В третьей главе Алексей Каптерев делится секретами публичного выступления: как вести себя на публике, держать внимание, отвечать на вопросы и др.

Чтобы сфокусироваться на аудитории (особенно, если людей много), нужно две вещи:
  • Знать содержание своей презентации,
  • Смотреть на отдельных людей в зале, общаться с ними (не «вещать» в пустоту, абстрактно).


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



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


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

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


Студенты спрашивали: «Зачем нам делать презентации в вузе? Они нам не пригодятся в работе!». Но этот вопрос никогда не ставил меня в тупик. Я отвечал примерно так, как говорит мастер презентаций Алексей Каптерев в книге, которую советую прочитать каждому, кто выступает перед публикой.

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

https://habrahabr.ru/post/335518/


Метки:  

[Из песочницы] Получение записей телефонной книги с мобильного телефона без дисплея

Воскресенье, 13 Августа 2017 г. 15:17 + в цитатник
Это скорее развлекательная история для тех, кто так же, как и я, не является специалистом в телефонах и восстановлении данных.

Однажды сотрудник принёс телефон Fly Ezzy Trendy 3.

image
(по его версии телефон начал первый, но сотрудник оказался сильнее)

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

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

Проверили, вроде включается. Во всяком случае, загорается подсветка клавиатуры.

Лезем в гугл и узнаём, что телефон работает на процессоре MediaTek MT6261D. Смотрим какие сервисные программы используются для работы с устройствами на базе таких процессоров. Выбираем MAUI META и заодно качаем пакет драйверов для устройств на базе процессоров MTK.

Тут я заинтересовался названием программы
И если META это Mobile Engineering Testing Architecture, как следует из найденой документации, то с MAUI не совсем понятно.

Нагуглил вот такие варианты:

  • Most Advanced User Interface
  • Multimodal Affective User Interface
  • Multimedia Application User Interface

Но это всё лирика.

Ставим драйвера, запускаем MauiMETA, выбираем FAT Editor, подключаем телефон и видим файловую систему телефона.

image

Копируем на компьютер содержимое NVRAM\NVD_DATA и начинаем усиленно его изучать. Оказалось, что нам нужны всего два файла MP0C_003 (здесь хранятся имена) и MP0H_006 (здесь хранятся номера телефонов). Так же, там был файл с смсками MPA3_001, но они нам были не нужны.

Будем использовать Frhed. Определяем размеры записей в этих файлах.

image
(вот здесь хорошо видно, где заканчиваются данные и идут пустые записи)

Формат записи в файле с именами:

  • 44 байта на одну запись
  • 2 последних байта под контрольную сумму
  • сами записи в UTF-16LE

Формат записи в файле с телефонами:

  • 38 байт на одну запись
  • каждая запись начинается с 0x00 0x00 0x01 0x00
  • 2 последних байта под контрольную сумму
  • сами записи в ASCII

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

Довольный владелец телефона ушёл со списком своих контактов в закат.

P.S. Из спортивного интереса решил проверить действительно ли последние два байта каждой записи являются какой-то контрольной суммой и если да, то каков её алгоритм.

Читал про 16-битные контрольные суммы типа CRC16 и безуспешно подбирал ту, которая подошла бы мне. Запарился и решил использовать «помощь зала» «звонок другу», который предположил, что всё намного проще и там может использоваться простая сумма всех байт записи.

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

Простенький скрипт



Проверка контрольных сумм на примере файла с именами



Надеюсь, что кому-то эта заметка поможет, а кого-то просто позабавит.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335528/


Метки:  

[Из песочницы] Безопасный OpenVPN на VPS за несколько минут

Воскресенье, 13 Августа 2017 г. 12:12 + в цитатник

Введение


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

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

Скрипт создавался для машин с CentOS 7.x или Ubuntu Server 17.x, использование на Ubuntu 16.x. возможно, но там OpenVPN 2.3.x в репозиториях. При необходимости можно добавить другие дистрибутивы, но обычно при покупке VPS можно выбрать систему и это не так важно.

Скрипт написан на bash за пару часов, возможны ошибки и наверняка что-то можно было реализовать проще и лучше.

Запускайте скрипт на свежей машине, он перезаписывает правила iptables и конфигурацию OpenVPN. И да, в правилах iptables разрешен порт ssh 22, если вы поменяли его на другой, не забудьте поменять порт в скрипте.

Особенности


  1. По умолчанию рекомендуется cipher AES-256-GCM (что достаточно безопасно на данный момент);
  2. По умолчанию используется auth SHA256 (вместо дефолтного SHA1);
  3. По умолчанию для OpenVPN 2.4.x используется tls-crypt (что усложняет обнаружение трафика OpenVPN);
  4. По умолчанию использует Google DNS и блокировку локальных DNS (setenv opt block-outside-dns) для предотвращения DNS Leak;
  5. Создаются все нужные правила в iptables и ip6tables;
  6. Есть поддержка IPv6.

Как пользоваться


Использовать скрипт очень просто, скачайте файл openvpnsetup.sh на ваш VPS, дайте ему права на запуск chmod +x openvpnsetup.sh и запустите ./openvpnsetup.sh. В результате вы получаете настроенный сервер, готовый к работе на выбранном вами порту.

В папке /etc/openvpn создается скрипт newclient.sh, который нужен для создания файлов конфигурации клиентской части, использовать его так же просто — ./newclient.sh clientname. Результатом будет файл /etc/openvpn/bundles/clientname.ovpn, который сразу можно использовать на клиенте, просто положите его в папку config (в случае использования на Windows) на вашей машине.

Если вы захотите пересоздать сервер, просто удалите все из папки /etc/openvpn и запустите скрипт заново (естественно, клиентские сертификаты надо будет перевыпустить).

Советы по выбору VPS для OpenVPN


  1. В первую очередь смотрим на цену, можно найти предложения за $3-4 в месяц, что дешевле многих VPN сервисов;
  2. Выбирайте VPS ближе к вам географически, если хотите иметь приемлемую скорость через VPN. Чем меньше пинг от вас до VPS, тем лучше скорость;
  3. Выбирайте минимальную конфигурацию. OpenVPN не использует больше одного ядра и может работать на 256MB памяти. Минимального дискового пространства в 3-5GB так же вполне достаточно;
  4. Некоторые VPS ограничены по трафику, но обычно это 1TB в месяц, если вы планируете использовать больше, рассмотрите другие тарифные планы;
  5. Перед тем как оформить заказ на VPS, уточните разрешена ли загрузка торрентов (при условии, что они вам нужны, конечно);
  6. Так же можно уточнить включены ли TUN/TAP устройства в системе. В скрипте есть проверка на это, но лучше уточнить до покупки, возможно их и нельзя будет включить через поддержку провайдера VPS;
  7. Наличие IPv6 адреса, скрипт позволяет настроить сервер с поддержкой IPv6 и возможно вы захотите иметь возможность посещать IPv6 ресурсы через VPN.

Скрипт доступен на GitHub.

Бонус: результат проверки анонимности на 2ip.ru:

image

Проверка на WITCH?:

image

Проверка на DNS Leak:

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

https://habrahabr.ru/post/335516/


Метки:  

Изоляция css стилей с помощью компонентного подхода

Воскресенье, 13 Августа 2017 г. 10:00 + в цитатник
Каждый раз, когда приходится создавать какой-то элемент, возникает небольшая проблема с придумыванием имени класса элемента, потому что мы хотим назвать его понятным именем, отражающим смысл и назначение этого элемента. Также, должны учесть то, что имя css-селектора не должно пересекаться с другими стилями.

Для того чтобы победить эту проблему, были разработаны разные методологии организации кода в css, но не все фронтендеры пользуются этими методологиям, и не все они идеальны.
Когда у нас в макете много разных по оформлению блоков, которые несут в себе один смысл, использовать понятное имя становится сложно. Чтобы добиться нужного результата приходится добавлять к имени еще что-то. Это все может сделать код трудным для восприятия (как длиннющие названия классов в беме).
Если вам посчастливилось присоединится к разработке какого-то проекта, то, возможно вы сталкивались с такой ситуацией когда стили написанные вами, пересекаются с теми, которые уже есть и используются в проекте. Самое неприятное, что это может всплыть не сразу, а когда всплывает, не всегда понятно откуда ноги растут.

Важную роль во всем этом играет еще то, как организована структура проекта. Чаще всего можно встретить свалку файлов в каталоге css(и не только там), тому кто пришел в проект бывает совсем не очевидно, в каком файле лежит нужный стиль и как стили одного файла влияют на стили другого файла. Хотелось бы верить, что когда все браузеры научатся понимать стандарты web components, проектов с помойной структурой станет меньше, и эти проблемы исчезнут.
Не смотря на то, что пока браузеры не всё умеют, много чего уже реализовано в компонентом стиле с помощью разных библиотек и полифилов, и это отлично работает, причем давно! Но бывают задачи, в которых использование мощных фреймворков и библиотек просто не нужно. К таким задачам можно отнести создание шаблонов под всякие вордпрессы, опенкарты, битриксы и прочие движки.

Как делают другие?


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

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

Мне нравится как подошли к этому вопросу разработчики Angular. Каждый компонент изолирован, стили внутри компонента никогда не пересекутся со стилями другого компонента, даже если они будут иметь одинаковое имя класса. Это достигается путем добавления уникального рандомного атрибута к каждому тегу элемента. Этот же атрибут добавляется к каждому классу в css. Чтобы не пугать тех, кто не знаком с Angular, добавлю, что исходный код компонента html и css является “чистым”, уникальные атрибуты добавляются при сборке приложения. Все файлы лежат отдельно друг от друга.

Пару слов про новый велик


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

Чтобы в проекте был порядок, необходимо разбить каждый элемент макета на отдельные компоненты из которых потом будут собираться страницы. Думаю, что всем понятно, в чем сила компонентов. Если нет, то тут learn.javascript.ru/webcomponents-intro коротко и ясно объясняется.

Структура проекта


Каждый компонент должен находится в своем каталоге. Имя каталога является именем компонента и используется в качестве префикса генерируемого атрибута. Все компоненты, должны лежать в каталоге components.
В каждом компоненте должен лежать файл html и css, если есть какая-то логика, то, там же следует разместить js файл.
Каждый компонент должен иметь свой тег. Желательно, чтобы в теге был дефис, например:

Такие правила заложены в стандарте custom elements, который пока мало где работает caniuse.com/#search=Custom%20Elements, но это не беда, рано или поздно заработает везде.
Свой тег компонента поможет лучше понимать что происходит в коде. Для демонстрации работы плагина и самого подхода, я подготовил крохотный пример.

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

Вот такая получилась структура проекта:

После отработки всех gulp тасков, можно будет увидеть во что превратился код.


Код примера:
github.com/A50/encapsulateHtmlCss
Плагин:
www.npmjs.com/package/gulp-encapsulate-htmlcss
Как думаете, такой подход жизнеспособен?

Никто ещё не голосовал. Воздержался 1 человек.

Стали бы вы применять такой подход в своих проектах?

Никто ещё не голосовал. Воздержался 1 человек.

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

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

https://habrahabr.ru/post/335510/


Метки:  

Использование ImGui с SFML для создания инструментов для разработки игр

Воскресенье, 13 Августа 2017 г. 09:52 + в цитатник

Привет, Хабр!
Данная статья — вольный перевод моей статьи на русский с некоторыми небольшими изменениями и улучшениями. Хотелось бы показать как просто и полезно использовать ImGui с SFML. Приступим.



Введение


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


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



Редактор уровней



Консоль Lua



Редактор анимаций


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


ImGui и концепция immediate GUI


Immediate mode GUI немного отличается от классической методики программирования интерфейсов, которая называется retained mode GUI. ImGui виджеты создаются и рисуются в каждом кадре игрового цикла. Сами виджеты не хранят внутри себя своё состояние, либо хранят абсолютно минимальный необходимый минимум, который обычно скрыт от программиста.


В отличие от того же Qt, где для создания кнопки нужно создавать объект QPushButton, а затем связывать с ней какую-нибудь функцию-callback, вызываемую при нажатии, в ImGui всё делается гораздо проще. В коде достаточно написать:


if (ImGui::Button("Some Button")) {
    ... // код, вызываемый при нажатии кнопки
}

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


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


Советую посмотреть вот это видео Кейси Муратори про ImGui, если вы хотите узнать чуть больше о данной методике.


Итак, каковы же достоинства ImGui?


  • MIT-лицензия
  • Очень быстрая и занимает мало памяти
  • Постоянно обновляется и расширяется
  • Почти не производит динамическую аллокацию/деалокаццию (и это можно контролировать, устанавливая каким образом ImGui будет получать необходимую память)
  • Очень портабельна: есть множество биндингов для различных библиотек и платформ
  • Очень легко расширяется путём создания новых виджетов на основе существующих, либо написанных с нуля.

Настройка


Итак, начнём


  1. Создайте простую программу на SFML, которая показывает пустое окно. Если вы раньше этим не занимались, то можете воспользоваться туториалом.
  2. Скачайте ImGui.
  3. Скачайте ImGui SFML биндинг и положите его в папку, в которую скачали ImGui.
    Важно: добавьте содержимое imconfig-SFML.h в imconfig.h
  4. Добавьте папку ImGui в include директории вашего проекта
  5. Добавьте следующие файлы в билд вашего проекта:


    • imgui.cpp
    • imgui_draw.cpp
    • imgui-SFML.cpp
    • imgui_demo.cpp

  6. Если вы будете получать ошибки линковки, то залинкуйте OpenGL к своему проекту.

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


#include "imgui.h"
#include "imgui-sfml.h"

#include Graphics/RenderWindow.hpp>
#include System/Clock.hpp>
#include Window/Event.hpp>

int main()
{
    sf::RenderWindow window(sf::VideoMode(640, 480), "");
    window.setVerticalSyncEnabled(true);
    ImGui::SFML::Init(window);

    sf::Color bgColor;
    float color[3] = { 0.f, 0.f, 0.f };

    // здесь мы будем использовать массив char. Чтобы использовать
    // std::string нужно сделать действия, описанные во второй части
    char windowTitle[255] = "ImGui + SFML = <3";
    window.setTitle(windowTitle);

    sf::Clock deltaClock;
    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            ImGui::SFML::ProcessEvent(event);

            if (event.type == sf::Event::Closed) {
                window.close();
            }
        }

        ImGui::SFML::Update(window, deltaClock.restart());

        ImGui::Begin("Sample window"); // создаём окно

        // Инструмент выбора цвета
        if (ImGui::ColorEdit3("Background color", color)) {
            // код вызывается при изменении значения, поэтому всё
            // обновляется автоматически
            bgColor.r = static_cast(color[0] * 255.f);
            bgColor.g = static_cast(color[1] * 255.f);
            bgColor.b = static_cast(color[2] * 255.f);
        }

        ImGui::InputText("Window title", windowTitle, 255);

        if (ImGui::Button("Update window title")) {
            // этот код выполняется, когда юзер жмёт на кнопку
            // здесь можно было бы написать 
            // if(ImGui::InputText(...))
            window.setTitle(windowTitle);
        }
        ImGui::End(); // end window

        window.clear(bgColor); // заполняем окно заданным цветом
        ImGui::SFML::Render(target);
        window.display();
    }

    ImGui::SFML::Shutdown();
}

Вы должны увидеть что-то вроде этого:



Попробуйте изменить что-нибудь. Если кликнуть два раза на одно из полей RGB, то можно ввести соответствующее значение. Если одно из полей потянуть, то можно плавно изменять текущее введённое значение. Поле ввода позволяет изменить заголовок окна после нажатия на кнопку.



Отлично, теперь разберёмся как всё работает.


ImGui инициализируется вызовом ImGui::SFML::Init, при вызове в функцию передаётся ссылка на окно sf::RenderWindow. В этот момент также создаётся стандартный шрифт, который будет использоваться в дальнейшем. (см. раздел Fonts how-to в описании imgui-sfml, чтобы увидеть как использовать другие шрифты).


При выходе из программы важно вызывать функцию ImGui::SFML::Shutdown, которая освобождает ресурсы, которые использует ImGui.


В игровом цикле ImGui имеет две фазы: обновление и рендеринг.


Обновление состоит из обработки событий, обновления состояния ImGui и обновления/создания виджетов. Обработка событий происходит через вызов ImGui::SFML::ProcessEvent. ImGui обрабатывает события клавиатуры, мыши, изменения фокуса и размера окна. Обновление состояния ImGui производится в ImGui::SFML::Update, в неё передаётся delta time (время между двумя обновлениями), который ImGui использует для обновления состояния виджетов (например, для анимации). Также в данной функции вызывается ImGui::NewFrame, после вызова которой уже можно создавать новые виджеты.


Рендеринг ImGui осуществляется вызовом ImGui::SFML::Render. Очень важно создавать/обновлять виджеты между вызовами ImGui::SFML::Update и ImGui::SFML::Render, иначе ImGui будет ругаться на нарушение состояния.


Если вы рендерите реже, чем обновляете ввод и игру, то в конце каждой итерации вашего update необходимо также вызывать ImGui::EndFrame:


while (gameIsRunning) {
    while (updateIsNeeded()) {
        updateGame(dt);
        ImGui::SFML::Update(window, dt);
        ImGui::EndFrame();
    }
    renderGame();
}

Виджеты создаются путём вызова соответствующих функций (например, ImGui::InputInt или ImGui::Button). Если вызвать ImGui::ShowTestWindow, то можно увидеть много примеров использования ImGui, весь код можно найти в imgui_demo.cpp.


Полезные перегрузки функций для SFML


Для SFML в биндинге были созданы некоторые перегрузки функций, например в ImGui::Image и ImGui::ImageButton можно кидать sf::Sprite и sf::Texture, также можно легко рисовать линии и прямоугольники вызовом DrawLine, DrawRect и DrawRectFilled.


Заключение


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


P.S. Если возникнет интерес, то могу перевести и вторую часть туториала, которая рассказывает про использование ImGui с современным C++ и стандартной библиотекой. Советую обратить на статью внимание тем, кто решит использовать (или уже использует) ImGui: она показывает как просто решать основные проблемы ImGui и делать всё проще и безопаснее, чем это делается в C++03.

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

https://habrahabr.ru/post/335512/


Метки:  

Проклятые Земли — Улучшаем бег и опыт с напарниками

Суббота, 12 Августа 2017 г. 20:20 + в цитатник



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



Нам понадобятся ArtMoney, IDA, Hiew.

В действиях ничего сложного нет, здесь главное результат. Смещения приведены для версии 1.07.

Запускаем IDA, загружаем файл game.exe, ждем пока завершится анализ.
Запускаем стартер, убираем настройку «Полноэкранный режим».
Запускаем игру в отладчике, загружаем сохранение где уже можно взять напарника.
Берем напарника, выходим на карту.




Бег



Смотрим, сколько запаса сил у персонажа. Здесь это 54.
Запускаем ArtMoney. Ищем это значение. Тип «С точкой 4 байта».
Пробегаем сколько-нибудь и отсеиваем новое значение.
Повторяем сколько нужно, у меня сразу осталось одно значение.


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

Ставим на этот адрес брейкпойнт на запись в IDA. Перед этим обязательно надо сделать 'Pause process', иначе случаются вылеты.
Переключаемся на игру, отправляем персонажа в какую-нибудь точку, снимаем с паузы.

Брейкпойнт срабатывает.
.text:00548315 loc_548315:
.text:00548315                 fld     dword ptr [edi+14h]
.text:00548318                 fld     dword ptr [edi+18h]
.text:0054831B                 fmul    ds:dbl_73F088
.text:00548321                 fsubp   st(1), st
.text:00548323                 fst     dword ptr [edi+14h]
.text:00548326 >               fcomp   ds:flt_73B858
.text:0054832C                 fnstsw  ax
.text:0054832E                 test    ah, 1
.text:00548331                 jz      short loc_548388


Запись происходит в инструкции fst dword ptr [edi+14h]. Можно поставить Operand type — Floating point на этот адрес и на соседний [edi+18h].


Судя по значениям, там хранится:
[edi+14h] — текущее значение
[edi+18h] — максимальное значение

Видно, что максимальный запас сил персонажа умножается на константу dbl_73F088, и результат вычитается из текущего значения. Поэтому все персонажи бегают одинаково.
.rdata:0073F088 dbl_73F088      dq 6.666666666666666e-3
; 6.666666666666666e-3 = 0.006666666666666666 = 1/150

То есть персонаж может пробежать примерно 150 «шагов», но это не совсем шаги, которые видно на анимации, потому что вычитание происходит гораздо чаще. Полный запас сил расходуется за 9-10 секунд, значит вычитание вызывается 15 — 16.66 раз в секунду.
Скорее всего это зеленые точки, обозначающие путь.



В байтах эта константа записывается так:
4E 1B E8 B4 81 4E 7B 3F


Открываем game.exe в Hiew и переходим на адрес ".73F088".


Других констант с таким значением нет, ссылка на нее есть только в рассмотренном коде.

Можно ее поменять на любое значение, которое вам нужно. Я сделал себе в 3 раза меньше.
(1/150)/3 = 1/450 = 0.0022222222222222222

Для конвертации float/double в hex-представление можно воспользоваться онлайн-конвертером, например этим.

для справки
0.0066666666666666667 - 0x3F7B4E81B4E81B4F
0.006666666666666666  - 0x3F7B4E81B4E81B4E
0.0022222222222222222 - 0x3F623456789ABCDF
0.002222222222222222  - 0x3F623456789ABCDE


Получается красивое число 0x3F623456789ABCDF
DF BC 9A 78 56 34 62 3F

Заменяем, сохраняем, запускаем. Вот, так гораздо лучше.



Опыт



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

Смотрим, сколько опыта отображается у персонажа. Это можно сделать в режиме между картами. У меня это 116.


Ищем это значение. Здесь нужен тип «Целое 4 байта».

Это не исходная переменная, а вычисляемое значение, приведенное к int. Сам опыт хранится во float, но там другое значение, об этом ниже.

Теперь можно с кем-нибудь подраться. Выходить с карты чтобы посмотреть опыт нельзя, перезагружаться тоже, потому что память выделяется заново, и при повторном заходе на карту будут другие адреса. Надо прибавлять в уме. При этом надо учитывать округление. То есть, если за противника дается 5 очков опыта, и в команде 2 персонажа, то на экране будет отображаться опыт 2, но прибавлять надо 2.5 и брать целую часть.



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


Попробуем поставить брейкпойнты на запись на каждый адрес. Не забываем про «Pause process».

Подходит первый адрес. Остальные срабатывают по rep movsd.
.text:00522D00                 fld     dword ptr [ebx+700h]
.text:00522D06                 fadd    dword ptr [ebx+4]
.text:00522D09                 fsub    dword ptr [ebx+8]
.text:00522D0C                 fstp    [ebp+var_10]
.text:00522D0F                 fld     [ebp+var_10]
.text:00522D12                 fistp   [ebp+var_C]
.text:00522D15                 mov     edx, [ebp+var_C]
.text:00522D18                 mov     [edi+8], edx
.text:00522D1B >               mov     eax, [ebx+10h]
.text:00522D1E                 mov     [ebp+var_10], eax


Он срабатывает при беге или при бое любого из персонажей. Поэтому здесь лучше управлять только одним, а не группой, чтобы не путаться. В ebx находится адрес объекта персонажа. В [ebx+700h] находится 0.

Посмотрим значения.


387 — 271 = 116
Можно предположить, что это полученный и потраченный опыт, а текущий рассчитывается как их разность.

Уберем этот брейкпойнт и поставим новый на [ebx+4].

Выбираем всю группу и нападаем на противника.



Брейкпойнт срабатывает до того, как это будет видно на экране.

.text:005239D7                 fld     ds:dbl_73E128
.text:005239DD                 fld     dword ptr [esi+20h]
.text:005239E0                 fsub    ds:flt_73E124
.text:005239E6                 call    __CIpow
.text:005239EB                 fmul    [ebp+arg_4]
.text:005239EE                 fadd    dword ptr [esi+700h]
.text:005239F4                 fcom    ds:flt_73B858
.text:005239FA                 fst     dword ptr [esi+700h]
.text:00523A00                 fnstsw  ax
.text:00523A02                 test    ah, 41h
.text:00523A05                 jnz     short loc_523A19
.text:00523A07                 fadd    dword ptr [esi+4]
.text:00523A0A                 mov     dword ptr [esi+700h], 0
.text:00523A14                 fstp    dword ptr [esi+4]
.text:00523A17 >               jmp     short loc_523A1B


В [esi+4] новое значение опыта. В [ebp+arg_4] число 2.0. За молодого кабана дают 4.0, значит деление находится до вызова функции.

Выходим из функции через Ctrl+F7. Это обертка, выходим еще раз.

Смотрим чуть выше, там находится такой код.
.text:00591521 loc_591521:
.text:00591521                 fild    [ebp+var_18]
.text:00591524                 xor     esi, esi
.text:00591526                 cmp     eax, edi
.text:00591528                 mov     [ebp+var_14], esi
.text:0059152B                 fdivr   [ebp+arg_4]
.text:0059152E                 fstp    [ebp+arg_4]
.text:00591531                 jle     short loc_5915A5
.text:00591533                 jmp     short loc_591537


Также деление на число участников есть выше:
.text:00591324                 fdiv    [ebp+var_18]

Но я не нашел, когда выполняется этот код. Там трогать не будем.

Поставим брейкпойнт на 00591521 и поучаствуем в битве еще раз.
fdivr делит аргумент на st(0) и результат записывает в st(0): st(0) = arg / st(0). В st(0) находится значение [ebp+var_18], в котором находится 2 — число персонажей. В [ebp+arg_4] находится 4.0 — опыт за противника. При выполнении миссии начисление тоже происходит здесь.

Теперь через Hiew можно убрать код для деления. Из-за особенностей fdivr заменяем на nop все 3 команды (9 байт).
// было
.00591521: DB45E8                         fild        d,[ebp][-018]
.00591524: 33F6                           xor         esi,esi
.00591526: 3BC7                           cmp         eax,edi
.00591528: 8975EC                         mov         [ebp][-014],esi
.0059152B: D87D0C                         fdivr       d,[ebp][00C]
.0059152E: D95D0C                         fstp        d,[ebp][00C]
.00591531: 7E72                           jle        .0005915A5
.00591533: EB02                           jmps       .000591537

// стало
.00591521: 909090                         nop
.00591524: 33F6                           xor         esi,esi
.00591526: 3BC7                           cmp         eax,edi
.00591528: 8975EC                         mov         [ebp][-014],esi
.0059152B: 909090                         nop
.0059152E: 909090                         nop
.00591531: 7E72                           jle        .0005915A5
.00591533: EB02                           jmps       .000591537


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

Поехали!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335498/


Метки:  

[Перевод] Переосмысление PID 1. Часть 2

Суббота, 12 Августа 2017 г. 16:48 + в цитатник
В продолжение первой части…

Распараллеливание служб сокетов


Этот вид синхронизации при загрузке приводит к опоследовательности (последовательный запуск служб) существенной части процесса загрузки. Не было бы круто если бы мы могли избавиться от цены синхронизации и опоследовательности? Что ж, мы можем на самом деле избавиться. Для этого, нам необходимо понять, что на самом деле службы (демоны) требуют друг от друга, и почему их запуск откладывается. Для традиционных демонов (служб) Unix, есть только один ответ на этот вопрос: они ждут до тех пор, пока демон предоставляющий свои службы не будет готов принимать соединения. Обычно это AF_UNIX сокет в файловой системе, но это может таже быть AF_INET сокет. Для примера: клиенты D-Bus ждут /var/run/dbus/system_bus_socket, чтобы сконнектиться к нему, клиенты syslog ждут /dev/log, клиенты CUPS ждут /var/run/cups/cups.sock и NFS точки монтирования ждут /var/run/rpcbind.sock и порт IP портмаппера и т.д. А теперь задумайтесь об этом, на самом деле есть только одна вещь чего ждут остальные.

Так как это лежит в основе того, что следует далее, позвольте мне сказать это снова, но другими словами: если вы запускаете syslog и различных клиентов syslog одновременно, что произойдет в схеме обозначенной выше, так это то, что сообщения от клиентов будут добавлены в буфер /dev/log. До тех пор, пока буфер не переполнится, клиенты не должны ждать пока syslog закончит загрузку, они вытащат все сообщения из очереди и обработают их. Другой пример: мы запускаем D-Bus и несколько клиентов одновременно. Если отправлен синхронный запрос к шине, следовательно, будет ожидаться ответ, также синхронно, и произойдет то, что клиент будет заблокирован, тем не менее только один единственный этот клиент (пославший синхронный запрос) и только до тех пора пока D-Bus не отловит запрос и не обработает его.

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

Хороший момент, чтобы сделать паузу и пойти налить себе еще кофейка, и будьте уверены, что далее нас ждет материал еще более интересный.

Но в начале, давайте проясним несколько вещей: это какая-то новая логика? Нет, конечно же нет. Наиболее многообещающая система, которая работает как эта — это launchd от Apple: в MacOS прослушивание сокетов и запуск всех демонов делает launchd. Следовательно, все службы (демоны) могут запуститься параллельно и без необходимости в сконфигурированных зависимостях. И это в действительности изобретательное решение и главная причина почему MacOS предоставляет фантачтическое время загрузки. Я крайне рекомендую это видео где ребята из launchd объясняют, что и как они это делают. К сожалению, эта идея не была признана за пределами кампуса Apple.

Идея, на самом деле старее чем launchd. До launchd многоуважаемый inetd работал в схожем стиле: сокеты в основном создаются в демонах, которые запускает реальную службу (основной так сказать функционал), передавая дескриптор файла сокета функции exec(). Тем не менее, фокус inetd в основном был направлен не на локальные службы и демоны, а на службы Интернета (поздние реализации также поддерживают AF_UNIX сокет). inetd не был инструментом распараллеливания процесса загрузки системы или даже полезным для того чтобы получить правильные зависимости.

Для сокетов TCP inetd в основном использовался следующим образом: для каждого входящего соединения создавался новый экземпляр демона. Это означает, что для каждого соединения инициализировался и создавался новый процесс, что не назовешь рецептом для высокопроизводительных серверов. Тем не менее, с самого начала inetd также поддерживал и другой режим работы, где единственный демон создавался на первом соединении, и этот единственный экземпляр принимал последующие соединения (вот для чего был опции wait/nowait в inetd.conf, и эта была очень плохо документированная опция, к сожалению). Запуск демона на каждое соединение послужило для inted плохой репутацией как слишком медленного. Но это не совсем справедливо.

Распараллеливание служб шины


В современных службах в Linux прослеживается тенденция предоставлять службы через D-Bus взамен плоским AF_UNIX сокетам. Теперь, вопрос в следующем, можем ли мы применить ту же логику распараллеливания логики, как и для традиционных служб сокетов? Да, мы можем, D-Bus уже имеет все нужные механизм для этого: используя шину активации служба может быть запущена, когда в первый раз к ней обратятся. Шина активации также предоставляет нам минимальные функции синхронизации на каждый запрос, необходимый для запуска провайдеров и потребителей служб D-Bus одновременно: если мы хотим запустить Avahi одновременно с CUPS (отвлеченная заметка: CUPS использует Avahi чтобы обнаружить mDNS/DNS-SD принтеры), тогда мы можем запустить их одновременно, и если CUPS быстрее чем Avahi через логику активации шины, D-Bus поставит в очередь запрос до тех пора, пока Avahi занят, тем чтобы установить свое сервисное имя на шине.

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

И если это не великолепно, то тогда я не знаю, что великолепно!

Продолжение следует…
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335488/


Метки:  

Информационная экономика: почему стоимость технологических компаний так высока

Суббота, 12 Августа 2017 г. 15:00 + в цитатник
Инвесторы всё чаще предпочитают вкладываться в нематериальные активы (intangible investment), а не в компании, производящие промышленное оборудование, оснащение и другие материальные ценности (tangibles). Компании в США владеют нематериальными активами, общая сумма которых превышает $8 трлн. Это почти половина стоимости индекса S&P 500 на момент проведения исследования.

image

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

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

Как формируется оценка бизнеса в 21 веке


Учетные политики, которые организации используют для управления своими экономическими процессами, не подходят для современных нематериальных активов. Это создает причину для беспокойства при оценки акций. Регулирующие инструменты, такие как МСФО, признают нематериальные активы только в момент совершения сделки, например покупки. Такой стандарт не учитывает нематериальные активы компании, которые формируют ее акционерную стоимость. Значимость возрастает, когда из $89 трлн цены предприятия $30,1 трлн считается «нераскрытой стоимостью».

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

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

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

Основная проблема


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

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

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

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

Вывод


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

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

Другие материалы по теме финансов и фондового рынка от ITinvest:


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

https://habrahabr.ru/post/335492/


Метки:  

[Из песочницы] Разработка telegram бота с использованием Spring

Суббота, 12 Августа 2017 г. 14:43 + в цитатник

Пишите телеграмм ботов? Ваша производительность разработки желает лучшего? Ищите чего-то нового? Тогда прошу под кат.



Идея заключается в следующем: слямзить архитектуру spring mvc и перенести на telegram api.
Выглядеть должно как-то так:


@BotController
public class SimpleOkayController {
    @BotRequestMapping(value = "/ok")
    public SendMessage ok(Update update) {
        return new SendMessage()
                .setChatId(update.getMessage().getChatId())
                .setText("okay bro, okay!");
    }
}

или


Пример с бинами
@BotController
public class StartController {
    @Autowired
    private Filter shopMenu;

    @Autowired
    private PayTokenService payTokenService;

    @Autowired
    private ItemService itemService;

    @BotRequestMapping("/shop")
    public SendMessage generateInitMenu(Update update) {
            return  new SendMessage()
                    .setChatId(update.getMessage().getChatId().toString())
                    .setText("Товары моего магазинчика!")
                    .setReplyMarkup(shopMenu.getSubMenu(0L, 4L, 1L)); // <--
    }

    @BotRequestMapping(value = "/buyItem", method = BotRequestMethod.EDIT)
    public List bayItem(Update update) {
        ....................
        Item item = itemService.findById(id); // <--

        return Arrays.asList(new EditMessageText()
                .setChatId(update.getMessage().getChatId())
                .setMessageId(update.getMessage().getMessageId())
                .setText("Подтвердите ваш выбор, в форме ниже"),

                new SendInvoice()
                        .setChatId(Integer.parseInt(update.getMessage().getChatId().toString()))
                        .setDescription(item.getDescription())
                        .setTitle(item.getName())
                        .setProviderToken(payTokenService.getPayToken())
                        ........................
                        .setPrices(item.getPrice())
        );
    }

}

Это даёт следующие преимущества:


  • Не надо писать кастомную логику для выбора обработчика сообщения от пользователя
  • Возможность инжектить разлиные бины в наш @BotController
  • Как следствие из предыдущих двух пунктов — существенное сокращение объемов кода
  • Потенциально (хотя я этого еще не сделал) аргументы кастомного метода обработчика, могут быть выражены в виде тех аргументов, которые действительно нужны!
  • Возможность создавать серьезные энтерпрайз решения, используя spring

Давайте теперь посмотрим как это можно завести в нашем проекте


Аннотации
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface BotController {
    String[] value() default {};
}

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface BotRequestMapping {
    String[] value() default {};
    BotRequestMethod[] method() default {BotRequestMethod.MSG};
}

Создаем свой контейнер обработчиков в виде обычной HashMap


Контейнер
public class BotApiMethodContainer {
    private static final Logger LOGGER = Logger.getLogger(BotApiMethodContainer.class);

    private Map controllerMap;

    public static BotApiMethodContainer getInstanse() {
        return Holder.INST;
    }

    public void addBotController(String path, BotApiMethodController controller) {
        if(controllerMap.containsKey(path)) throw new BotApiMethodContainerException("path " + path + " already add");
        LOGGER.trace("add telegram bot controller for path: " +  path);
        controllerMap.put(path, controller);
    }

    public BotApiMethodController getBotApiMethodController(String path) {
        return controllerMap.get(path);
    }

    private BotApiMethodContainer() {
        controllerMap = new HashMap<>();
    }

    private static class Holder{
        final static BotApiMethodContainer INST = new BotApiMethodContainer();
    }
}

В контейнере будем хранить контроллеры обертки (для пары @BotController и @BotRequestMapping)


Контроллер обертка
public abstract class BotApiMethodController {
    private static final Logger LOGGER = Logger.getLogger(BotApiMethodController.class);

    private Object bean;
    private Method method;
    private Process processUpdate;

    public BotApiMethodController(Object bean, Method method) {
        this.bean = bean;
        this.method = method;

        processUpdate = typeListReturnDetect() ? this::processList : this::processSingle;
    }

    public abstract boolean successUpdatePredicate(Update update);

    public List process(Update update) {
        if(!successUpdatePredicate(update)) return null;

        try {
            return processUpdate.accept(update);
        } catch (IllegalAccessException | InvocationTargetException e) {
            LOGGER.error("bad invoke method", e);
        }

        return null;
    }

    boolean typeListReturnDetect() {
        return List.class.equals(method.getReturnType());
    }

    private List processSingle(Update update) throws InvocationTargetException, IllegalAccessException {
        BotApiMethod botApiMethod = (BotApiMethod) method.invoke(bean, update);
        return botApiMethod != null ? Collections.singletonList(botApiMethod) : new ArrayList<>(0);
    }

    private List processList(Update update) throws InvocationTargetException, IllegalAccessException {
        List botApiMethods = (List) method.invoke(bean, update);
        return botApiMethods != null ? botApiMethods : new ArrayList<>(0);
    }

    private interface Process{
        List accept(Update update) throws InvocationTargetException, IllegalAccessException;
    }
}

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


Для этого реализуем специальный бин — BeanPostProcessor. Это дает возможность отлавливать бины во время их инициализации. Наши контроллеры имеют scope по умолчанию — синглтон, значит инициализироваться они будут со стартом контекста!


TelegramUpdateHandlerBeanPostProcessor
@Component
public class TelegramUpdateHandlerBeanPostProcessor implements BeanPostProcessor, Ordered {
    private static final Logger LOGGER = Logger.getLogger(TelegramUpdateHandlerBeanPostProcessor.class);

    private BotApiMethodContainer container = BotApiMethodContainer.getInstanse();
    private Map botControllerMap = new HashMap<>();

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Class

https://habrahabr.ru/post/335490/


Метки:  

Поиск сообщений в rss_rss_hh_new
Страницы: 1437 ... 1093 1092 [1091] 1090 1089 ..
.. 1 Календарь