[Из песочницы] Форматы электронной подписи

Статья посвящена обзору стандартов СMS (Cryptographic Message Syntax) для подписанных сообщений.

Для чего нужен
Стандарт CMS описывает структуру криптографических сообщений, включающих в себя защищенные данные вместе со сведениями, необходимыми для их корректного открытия или использования. Например, в сообщении размещаются защищенные данные, информация об алгоритме хеширования и подписи, времени подписи, сертификате открытого ключа, цепочке сертификации и т.д. Некоторые из указанных атрибутов носят опциональный характер, но приложение может само определить необходимость их наличия. У каждого алгоритма есть набор параметров, который должен быть согласован на обеих сторонах: для ГОСТ 34.10-2001, помимо открытого ключа, это модуль p, коэффициенты эллиптической кривой a и b и порядок циклической подгруппы точек эллиптической кривой q. И все это нужно каким-то образом передать адресату сообщения.

RSA Laboratories в серии своих стандартов криптографии с открытом ключом (PKCS) предложила решение этой проблемы путем определения синтаксиса для защищенных сообщений в следующих стандартах:
Развитием этих стандартов стал стандарт CMS. CMS кроме определенной заголовком статьи подписи поддерживает операции шифрования, хеширования и вычисления имитовставки, в том числе и по российским алгоритмам (RFC 4490), а также множественную инкапсуляцию. Последнее означает, что сообщение формата CMS может лежать внутри другого CMS сообщения.

Всего CMS поддерживает шесть типов данных:
  • просто данные (data),
  • данные с электронной подписью (signed data),
  • упакованные данные (enveloped data),
  • хешированные данные (digested data),
  • зашифрованные данные (encrypted data),
  • данные с проверкой подлинности (authenticated data).
В рамках статьи мы подробно рассмотрим только данные с электронной подписью (signed data).

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

Стандарт CMS (PKCS #7 и RFC 5652): теория
Чуть истории
Синтаксис криптографических сообщений (CMS) впервые был определен в PKCS #7, который позже был опубликован в качестве рекомендаций RFC 2315 «PKCS #7: Cryptographic Message Syntax Version 1.5». Спустя еще несколько версий RFC в сентябре 2009 года был принят RFC 5652 «Cryptographic Message Syntax (CMS)», который является действующим стандартом на данный момент.
Под спойлером иллюстрируется тяжелая судьба стандарта.
Смотреть
Эволюция PKCS#7/CMS

Подпись в CMS-формате (signed data type)
Подпись, описанная стандартом CMS, характеризуется следующими особенностями:
  1. Данные могут быть подписаны несколькими сторонами (множественная подпись). В таком случае в сообщении будут присутствовать несколько структур SignerInfo с информацией о подписывающих сторонах: значением подписи и необходимой для проверки ее подлинности информацией.
  2. Тип данных никак не регламентируется, лишь уточняется, что в качестве данных может быть сообщение формата CMS, то есть подписанное Алисой сообщение может быть целиком подписано Бобом.
  3. Подписывать можно не только данные, но и некоторые атрибуты сообщения – хеш сообщения (digest message), время подписи (signing time), значение другой подписи (countersignature).
  4. Открытый ключ подписывающей стороны может быть несертифицированным.
  5. Подпись может отсутствовать и вовсе.
Данные с электронной подписью используются не только для подписи содержимого и часто используются для распространения сертификатов и списков отзыва сертификатов (Certification Revocation List, CRL). В таком случае подписываемые данные отсутствуют, а поля Certificates и CRLs, наоборот, присутствуют.

Подписанное Алисой сообщение в формате CMS будет иметь следующий вид (серым отмечены необязательные атрибуты):


  • Версия синтаксиса CMS Version зависит от сертификатов, типа подписываемых данных и информации о подписывающих сторонах
  • Digest Algorithms включает в себя идентификаторы используемых алгоритмов хеширования и ассоциированные с ними параметры.
  • Encapsulated Content содержит подписываемые данные (Content) вместе с их типом (Content Type). Содержимое может отсутствовать, тип – нет.
  • Certificates предназначен для цепочки сертификатов, отражающих путь сертификации от центра сертификации, выдавшего сертификат, до каждой из подписывающих сторон. Также могут присутствовать сертификаты подписывающих сторон.
  • CRLs (Certificate Revocation List) предоставляет информацию о статусе отзыва сертификатов, достаточную для определения валидности сертификата подписывающей стороны.
  • Информация о каждой подписывающей стороне содержится в структурах типа Signer Info, которых может быть любое количество, в том числе и нулевое (в случае отсутствия подписи).
    • Версия синтаксиса CMS Version определяется значением Signer ID.
    • Signer ID определяет открытый ключ подписывающей стороны (subjectKeyIdentifier) или сертификат его открытого ключа, необходимый для проверки подлинности подписи (issuerAndSerialNumber).

    • Digest Algorithm определяет алгоритм хеширования и все ассоциированные с ним параметры, используемые подписывающей стороной.
    • В Signed Attributes помещаются атрибуты, требующие подписи. Поле может отсутствовать только при подписи простых данных (Content Type = id-data), при подписи других данных (например, Content Type = id-SignedData) должно присутствовать с как минимум двумя обязательными атрибутами – типом (Content Type) и хешем данных (Message Digest).
    • Signature Algorithm содержит идентификатор алгоритма подписи вместе с его параметрами.
    • В Signature Value помещается значение подписанного закрытым ключом хеша от данных (Content) и атрибутов для подписи (Signed Attributes).
    • В Unsigned Attributes помещаются оставшиеся атрибуты, не требующие подписи.
Если Боб решает целиком подписать полученное от Алисы сообщение, то используется механизм инкапсуляции, и сообщение будет выглядеть вот так:


CMS предлагает два интересных атрибута, расширяющих возможности обычной подписи: время подписи (Signing Time) и контрасигнатуру (Countersignature). Первый атрибут определяет предполагаемое время осуществления подписи, а второй предназначен для подписи другой подписи (подписывается хеш от значения подписи). Атрибут Countersignature представляет собой структуру Signer Info с отсутствующим в Signed Attributes атрибутом Content Type и обязательно присутствующим атрибутом Message Digest. Атрибут Countersignature может иметь свой собственный атрибут Countersignature.

Если Боб решит подписать только данные, переданные Алисой, и заодно подписать подпись Алисы, то сообщение будет иметь такой вид:


Галопом по Европам оставшимся типам
СMS предлагает еще несколько интересных типов сообщений, не охватываемых темой этой статьи. Поэтому буквально по паре слов об оставшихся типах для общей картины.
Упакованные данные (enveloped data) представляют собой зашифрованные данные вместе с зашифрованными для одного или более получателей ключами, которыми эти данные были зашифрованы. Комбинация зашифрованного сообщения с одним зашифрованным ключом шифрования для одного получателя называется цифровым конвертом. Данный тип используется в качестве конверта с (подписанными) данными для одного или нескольких получателей.
Хешированные данные (данные вместе со своим хешем) используются для проверки целостности сообщения и часто являются содержимым упакованных данных.
Зашифрованные данные часто используются для шифрования данных для локального хранилища, иногда с выработанным из пароля ключом шифрования.
Данные из аутентифицированного источника (данные с проверкой подлинности) включают в себя данные вместе с их MAC-кодом и зашифрованными ключами аутентификации для одного или нескольких получателей. Используются для защиты целостности сообщений для неограниченного количества получателей.

В следующей статье мы подробно остановимся на сообщениях типа enveloped data с использованием российских криптоалгоритмов.

CMS в реальной жизни
Стандарт CMS имеет немало воплощений в современном мире IT – на нем основаны:
  • стандарт защищенной электронной почты S/MIME (RFC 3851),
  • расширенные защиты для S/MIME (RFC 2634, кстати, тут описаны дополнительные атрибуты CMS и технология тройного «обертывания» на основе множественной инкапсуляции: данные подписываются, затем шифруются и снова подписываются),
  • расширенные форматы представления информации об аннулированных сертификатах (RFC 5940) и пр.
Закономерным развитием идей CMS для сообщений с электронной подписью cтал CAdES (CMS Advanced Electronic Signature), расширенный стандарт подписанных сообщений CMS, который также послужит темой для еще одной нашей статьи.

Как реализовать на практике?
Стандарт CMS/PKCS#7 с поддержкой российских криптоалгоритмов реализован в сертифицированных СКЗИ наших партнеров:
Кроме того, стандарт CMS с российской криптографией реализован в Open Source приложении OpenSSL.

Наша компания поддержала CMS c российской криптографией в продукте Рутокен Плагин. Рутокен предназначен для использования в браузерах, все криптографические операции производятся аппаратно, «на борту» USB-токена.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


[Из песочницы] Derby.js — новый взгляд на веб-разработку

Вы веб-разработчик?




В чем собственно проблема?

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

Сервер-ориентированные

Например: RoR, Django, Asp Net, Express.js
Генерируют html на сервере.
Такой подход хорош для статических страничек.
Но как только вы хотите сделать что-то интерактивное, то начинаете утопать в jQuery-коде.

Клиент-ориентированные

Например: Backbone.js, Knockout.js, Ember.js, Batman.js
Генерируют html прямо на клиенте из темплейтов. Код на клиенте структурирован.
Хорошо для интерактивных сайтов.
Не отменяет необходимость использовать сервер-ориентированный фреймворк, что ведет к дублированию кода (модели, валидация и т.д.)

Кросс-компилируемые

Например: GWT, Cappuccino
Позволяют писать всё на одном языке.
Очень большой уровень абстракции.
Шаг вправо, шаг влево — расстрел.

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

Давайте помечтаем

Что мы хотим от веб-фреймворка?

  • Один язык (Javascript) для повторного использования кода на сервере и клиенте
  • Генерация html первый раз на сервере (для быстрой загрузки), следующие разы на клиенте (для интерактивности)
  • MVC для структуры кода
  • Реактивная привязка вида и модели (изменения модели немедленно отражаются в html и наоборот)
  • Встроенная синхронизация данных между сервером и всеми клиентами
  • Offline

Такое бывает?

Да, Derby.js

github
twitter
Вопросы лучше всего задавать в Google Groups
Пример приложения: habitrpg

Создатели Derby.js: Nate и Brian

P.s.:
Основной конкурент — Meteor.
Из плюсов — ниже порог входа. Из минусов — не поддерживает npm и нет генерации html на сервере.
Подробное сравнение здесь.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Android компонент с нуля — 2 — Лупа для изображения

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

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

Подготовка

Создайте новый проект и класс «PZoom», в качестве предка используйте класс View.
Нам интересны следующие функции:
PZoom — конструктор класса;
onDraw — функция рисования, вызывается каждый раз когда необходимо перерисовать компонент;
onTouchEvent — функция отслеживания внешних событий, вызывается каждый раз когда пользователь нажимает пальцем на экран и поподает на компонент, а также когда водит пальцем по компоненту и также отжимает палец.
Упростим себе задачу, будем использовать только одну картинку заранее помещённую в папку Drawable с именем «img» (чем больше будет картинка тем более наглядный эффект вы получите). В началекласса объявим новый объект типа Drawable
<code class="java">private Drawable image; // Главная картинка
</code>
Далее в конструкторе, поместим в image нужную картинку и установим рамки:
<code class="java">image = context.getResources().getDrawable(R.drawable.img);
image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
</code>
Теперь пересоздадим процедуру рисования:
<code class="java">	@Override
	protected void onDraw(Canvas canvas) {
		 super.onDraw(canvas);
		 canvas.save(); // Сохранение тщекущих матриц (смещения, поворота и т.д....)

		 image.draw(canvas); // Указываем поверхность для рисования картинки
		 canvas.restore(); // Очищение матриц, приведение их в исходное состояние
	}
</code>
Переходим в главный класс приложения и модифицируем конструктор класса следующим образом:
<code class="java">	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(new PZoom(this));
	}

</code>
Эти действия создают класс Pzoom и определяют его в качестве основного, то есть теперь на экране будет отображаться только этот компонент.
Теперь если вы запустите приложение то увидите на экране только часть загруженной картинки, так как она не поместиться полностью на экран (картинка больше экрана).

Функционал

Для начала сделаем так чтобы по умолчанию картинка помещалась посреди экрана а её размеры были пропорциональны экрану. Для этого напишем отдельную функцию SetCenter, определяющую позицию картинки на поверхности, а также правильный множитель для пропорции.
Объявим дополнительные переменные в начале класса:
<code class="java">	int X = 0,Y = 0; // Позиции картинки на экране
	float scale = 0; // Множитель для пропорций
	int pX = 0, pY = 0; // Позиция пальца на экране
	int dWidth = 0, dHeight = 0; // Размеры компонента
</code>
Теперь тело самой функции (разжёвывать её нет смысла, это элементарная математика):
<code class="java">	void SetCenter(){
		// Вычисляем множитель для пропорции
		if(dWidth>dHeight) // 
			scale = (float)dHeight/image.getIntrinsicHeight();
		else
			scale = (float)dWidth/image.getIntrinsicWidth();

		// Позиция на экране
		if((dWidth-image.getIntrinsicWidth()*scale)>0){
			X = (int)((dWidth-(image.getIntrinsicWidth()*scale))/2/scale);
			Y = 0;
		} else {
			X = 0;
			Y = (int)((dHeight-(image.getIntrinsicHeight()*scale))/2/scale);
		}
	}
</code>
Теперь дополним функцию рисования виджета:
<code class="java">@Override	
	protected void onDraw(Canvas canvas) {
		 super.onDraw(canvas);
		 canvas.save(); // Сохранение тщекущих матриц (смещения, поворота и т.д....)
		 
		 if (dWidth==0){ // Проверка наличия данных в переменных размера виджета
			 dWidth = canvas.getWidth();
			 dHeight = canvas.getHeight();
		 }
		 
		 if (pX==0) { // Проверяем  позицию курсора
				SetCenter(); // Устанавливаем картинку в центре виджета
			}
		 
		 canvas.scale(scale, scale); // ZooM
		 canvas.translate(X,Y); // Смещение картинки
		 
		 image.draw(canvas); // Указываем поверхность для рисования картинки
		 canvas.restore(); // Очищение матриц, приведение их в исходное состояние
	}
</code>
В начале происходит проверка наличия данных в переменных размера виджета, если они равны нулю, то узнаём размеры виджета. Далее происходит проверка наличия данных в переменной позиции курсора, если она ровна нулю (палец пользователя не находится на виджете) то запускаем функцию центровки картинки. После этого происходит изменение размеров картинки в соответствии со значением растяжки. Затем происходит смещение картики. В конце отрисовывается картинка и сбрасываются матрицы.
Переходим к самому главному — изменению размера и положения картинки относительно нажатого пальца. Прево наперво следует переопределить процедуру позиционирования пальца на экране onTouchEvent:
<code class="java">	@Override
	public boolean onTouchEvent(MotionEvent event) {
		//Вытягиваем совершённое действие
		 pX=(int) event.getX();	// Позиция по X
		 pY=(int) event.getY();	// Позиция по Y
		 int Action=event.getAction();	// Действие
	 
		 // Поднятие пальца
		 if (Action==MotionEvent.ACTION_UP){
			 pX = 0;
			 pY = 0;
		 }

		 invalidate(); // Перерисовка виджета
		 return true;
	 }
</code>
Описывать не буду, кому интересно то обратитесь к первой статье. Осталось создать процедуру вычисления новой позиции картинки на экране, она будет иметь следующий вид:
<code class="java">	void NewPosition(){
		scale = 1; // Устанавливаем коэфициент растягивания
		
		// Вычисляем новые позиции картинки относительно экрана и нажатого пальца
		X = (int)((float)-image.getIntrinsicWidth()*((float)pX/dWidth)+((float)dWidth*((float)pX/dWidth)));
		Y = (int)((float)-image.getIntrinsicHeight()*((float)pY/dHeight)+((float)dHeight*((float)pY/dHeight)));
		
		// Проверка чтобы небыло сверху и слева белых мест
		if (X>0) X=0;
		if (Y>0) Y=0;
	}
</code>
Слегка меняем функцию отрисовки видежта, а именно — если переменная позиции курсора не пуста, то вычисляем новую позицию:
<code class="java">if (pX==0) { // Проверяем  позицию курсора
				SetCenter(); // Устанавливаем картинку в центре виджета
			} else {
				NewPosition(); // Устанавливаем картинку в новую позицию
			}
</code>
Если всё сделали правильно, то при нажатии на картинку она будет увеличиваться и перемещаться по экрану относительно пальца пользователя. Удачного тестирования!

Конечный вид класса картинки-лупы:
<code class="java">package com.gc986.photozoom;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.view.MotionEvent;
import android.view.View;

public class PZoom extends View {
	private Drawable image; // Главная картинка
	int X = 0,Y = 0; // Позиции картинки на экране
	float scale = 0; // Множитель для пропорций
	int pX = 0, pY = 0; // Позиция пальца на экране
	int dWidth = 0, dHeight = 0; // Размеры компонента
	
	public PZoom(Context context) {
		super(context);
		// Создание объекта главной картинки
		image = context.getResources().getDrawable(R.drawable.img);
		image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
	}
	
	@Override	
	protected void onDraw(Canvas canvas) {
		 super.onDraw(canvas);
		 canvas.save(); // Сохранение тщекущих матриц (смещения, поворота и т.д....)
		 if (dWidth==0){ // Проверка наличия данных в переменных размера виджета
			 dWidth = canvas.getWidth();
			 dHeight = canvas.getHeight();
		 }
		 
		 if (pX==0) { // Проверяем  позицию курсора
				SetCenter(); // Устанавливаем картинку в центре виджета
			} else {
				NewPosition(); // Устанавливаем картинку в новую позицию
			}
		 
		 canvas.scale(scale, scale); // ZooM
		 canvas.translate(X,Y); // Смещение картинки
		 
		 image.draw(canvas); // Указываем поверхность для рисования картинки
		 canvas.restore(); // Очищение матриц, приведение их в исходное состояние
	}

	/**Центровка картинки*/
	void SetCenter(){
		// Вычисляем множитель для пропорции
		if(dWidth>dHeight) // 
			scale = (float)dHeight/image.getIntrinsicHeight();
		else
			scale = (float)dWidth/image.getIntrinsicWidth();
		// Позиция на экране
		if((dWidth-image.getIntrinsicWidth()*scale)>0){
			X = (int)((dWidth-(image.getIntrinsicWidth()*scale))/2/scale);
			Y = 0;
		} else {
			X = 0;
			Y = (int)((dHeight-(image.getIntrinsicHeight()*scale))/2/scale);
		}
	}
	
	/**Определение новых позиций картинки*/
	void NewPosition(){
		scale = 1; // Устанавливаем коэфициент растягивания
		// Вычисляем новые позиции картинки относительно экрана и нажатого пальца
		X = (int)((float)-image.getIntrinsicWidth()*((float)pX/dWidth)+((float)dWidth*((float)pX/dWidth)));
		Y = (int)((float)-image.getIntrinsicHeight()*((float)pY/dHeight)+((float)dHeight*((float)pY/dHeight)));
		// Проверка чтобы небыло сверху и слева белых мест
		if (X>0) X=0;
		if (Y>0) Y=0;
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		//Вытягиваем совершённое действие
		 pX=(int) event.getX();	// Позиция по X
		 pY=(int) event.getY();	// Позиция по Y
		 int Action=event.getAction();	// Действие
		 // Поднятие пальца
		 if (Action==MotionEvent.ACTION_UP){
			 pX = 0;
			 pY = 0;
		 }

		 invalidate(); // Перерисовка виджета
		 return true;
	 }
}
</code>
Так должно получиться в идеале — http://youtu.be/GHB91_RzORY
Архив примера со всеми комментариями можете скачать по следующей ссылке — http://www.anprog.com/documents/Photo_Zoom.zip

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


[Из песочницы] Raspberry Pi в руках дилетанта или домашняя торрент-качалка

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


Шаг первый. Подготовка.

Для сервера, и работы вообще, нам понадобятся:
  • карта памяти*
  • блок питания
  • microUSB-кабель для питания платы
  • кабель HDMI или кабель с AV-разъемом
  • USB-клавиатура
  • переносной жесткий диск*
imageimage
Сама плата RasPi мало «кушает», но у нас будет подключен жесткий диск, значит питание нужно помощнее.
А конкретнее, напряжение в 5 вольт и ток в 2 ампера. Я взял обычный блок питания от компьютера.
На моем БП был 20-контактный разъем основного питания. Для платы на нужен контакт +5 VSB, фиолетового цвета на картинке. К нему я подключил два USB — один будет питать плату, а другой жесткий диск.
На фотографии, от фиолетового провода идет питание к двум USB, синий — земля, два замкнутых разъема — чтобы БП работал без материнской платы.(?)
Подсказка: Обычно, красный провод на USB — питание, черный — земля.
С питанием разобрались, теперь можно подключить экран к RasPi. Лучше для этого использовать HDMI-кабель и подключить плату к монитору или телевизору. HDMI лучше, т.к. картинка будет четкая.
Свою плату я подключил через AV к ТВ-тюнеру на компьютере.

Шаг второй. Установка дистрибутива на карту и настройка.

Для установки нам понадобится утилита Win32DiskImager. Скачать можно отсюда.
И образ системы Raspbian “wheezy”. Скачать можно отсюда.

(!) Есть образ уже установленной системы с настроенным торрентом. Можно ставить на карточку только с объемом не менее 8Gb. Вы можете его скачать отсюда, но лучше поставить чистую систему.

Итак, приступим:
  1. Подключите карту памяти к компьютеру
  2. Запустите Win32DiskImager
  3. В поле Image File укажите путь в скаченному образу Raspbian “wheezy”*
  4. Выберите в пункте Device букву вашей карты
  5. Нажмите кнопку Write и дождитесь окончания записи образа.
  6. Безопасно извлеките карту

Теперь вставляем карту памяти в RasPi и запускаем. В итоге перед нами появляется такое меню:


Рассмотрим его пункты:
  1. Expand Filesystem — увеличить размер основного раздела на всю карту. Запускаем сразу.
  2. Change User Password — задать пароль учетной записи. Учетная запись по умолчанию — «pi».
  3. Enable Boot to Desktop — грузиться в графический интерфейс. Можно отключить, т.к. все делается через консоль.
  4. Internationalisation Options — установка языка системы. Русский присутствует.
  5. Enable Camera — включение/отключение поддержки камеры.
  6. Add to Rastrack — добавить свое устройство в общую базу. Нет необходимости.
  7. Overclock — повысить мощность процессора. Лучше не трогать, хотя страшного ничего не случится.(?)
  8. Advanced Options — расширенные настройки.
    1. Overscan — настройка вылета развертки.
    2. Hostname — имя вашего мини-сервера в сети.
    3. Memoy Split — выделение памяти графическому процессору (?). Если граф. интерфейс отключен — 16Мб.
    4. SSH — удаленное управление. Включить.
    5. Update — текущего дистрибутива.
  9. About raspi-config — информация об этом меню настроек.
После изменения нужных вам настроек, жмем Finish*.
Система уходит в перезагрузку, а после просит ввести имя пользователя — «pi» и пароль. Если не поставили свой, то пароль по умолчанию «raspberry».

Шаг третий. Установка торрента и подключение HDD.

Сперва увеличим размер swap*

Вводим:
sudo nano /etc/dphys-swapfile
Открывается файл. В нем значение CONF_SWAPSIZE меняем на 256 и жмем [Ctrl+O], далее [Enter] и для выхода [Ctrl+X].

Теперь монтируем диск.
Т.к. я иногда отключаю переносной HDD от RasPi и использую его по прямому назначению, у меня он в файловой системе NTFS. Что не есть хорошо, ведь мы на линуксе, значит диск должен быть в файловой системе Ext, но эта система в windows не работает без дополнительного софта. Так что я не буду расписывать процесс форматирования в ext, благо в интернете можно найти, будем использовать NTFS.

Вернемся к монтированию.
1. Вводим в консоль:
sudo apt-get install ntfs-3g

2. Создаем папку, к которой будем монтировать HDD
sudo mkdir /mnt/usb_hdd

3. Даем полный доступ к папке всем группам.
sudo chmod 777 /mnt/usb_hdd
4. Открываем файл:
sudo nano /etc/fstab
5. Прописываем в конец файла:
/dev/sda1 /mnt/usb_hdd ntfs-3g defaults,rw 0 1
это дает автоматическое монтирование HDD при старте системы.
И жмем [Ctrl+O], далее [Enter] и для выхода [Ctrl+X].

Устанавливаем торрент-клиент Transmission.
В консоли:
<code class="bash">sudo apt-get install transmission-daemon
</code>
Теперь меняем настройки, но для этого торрент нужно остановить:
<code class="bash">sudo /etc/init.d/transmission-daemon stop
</code>
теперь откроем файл настроек:
<code class="bash">sudo nano /etc/transmission-daemon/settings.json
</code>

Основные опции:
  1. download-dirменяем на "/mnt/usb_hdd" и файлы будут закачиваться на HDD.
  2. download-limit — лимит скорости закачки в Кб/с.
  3. rpc-enabled — удаленное управление. Ставим " true"
  4. rpc-authentication-required — аутентификацию для удаленного управления. Я отключил, от кого прятаться в локальной сети?
  5. rpc-usernam — логин для удаленного управления. Сделайте пустым, если отключили аутентификацию.
  6. rpc-password — пароль для удаленного управления. При запуске торрента пароль шифруется. Сделайте пустым, если отключили аутентификацию.
  7. rpc-whitelist-enabled — включить список разрешенных IP-адресов. Меняем на false.
  8. rpc-port — порт для доступа к удаленному управлению. Меняем на 9091.
  9. peer-limit-global — максимальное количество подключенных пиров на все торренты.
  10. peer-limit-per-torrent — количество пиров на один торрент.
  11. peer-port — порт для раздач. Можете поменять на свой, но в любом случае его нужно открыть в настройках модема.
  12. download-queue-size — количество одновременных закачек. Есть вероятность зависания transmission при большом количестве.
После изменения настроек жмем [Ctrl+O], далее [Enter] и для выхода [Ctrl+X]. И запускаем Transmission командой:
<code class="bash">sudo /etc/init.d/transmission-daemon start
</code>
Теперь перезагружаемся:
<code class="bash">sudo reboot
</code>

Как управлять торрентом?
Можно получить доступ к веб-интерфейсу для этого нужно ввести в адресную строку браузера ip-адрес RasPi и, через двоеточие, порт transmission. Например:
<code class="html">http://192.168.1.42:9091
</code>
Еще можно воспользоваться программой Transmission Remote GUI(есть ниже).
В ней тоже нужно прописать IP и порт. А также логин и пароль, если вы поставили их запрос в настройках transmission раннее.

Послесловие.


Что если нет сети, а кабель воткнут?
Проверить наличие сети можно командойping.
Например:
<code class="bash">ping habrahabr.ru
</code>
Выйти можно командой [Ctrl+C].
Если ничего не происходит, то у вас нет сети. Тогда пишем:
<code class="bash">sudo nano /etc/network/interfaces
</code>
И меняем
<code class="bash">iface eth0 inet dhcp</code>
на
<code class="bash">iface eth0 inet static</code>
и добавляем после этого:
<code class="bash">address 192.168.1.42 
netmask 255.255.255.0 
gateway 192.168.1.1
</code>
address — IP адрес
netmask — маска подсети
gateway — основной шлюз

Команды:
sudo — ставится перед командами, и запускает их от имени администратора. {вернуться}
sudo reboot — перезагрузка.
sudo halt — выключение.
Ctrl+C — выход из открытой консольной программы.
Shift+Ins — вставить текст в консоль.
Ctrl+Ins — копировать выделенный текст из консоли.
стрелки вверх и вниз — листают набранные ранее команды.
nano — консольный текстовый редактор. {вернуться}
sudo apt-get install [имя пакета] — установка пакета*. {вернуться}
sudo mkdir [имя папки] — создание папки.{вернуться}
sudo chmod [значение] — изменение прав групп для папки.[подробнее] {вернуться}

Список программ для управления RasPi из Windows:
  • WinSCP — клиент, для подключения к файловой системе нашего мини-сервера по SFTP. [Скачать]
  • PuTTY — клиент, для удаленного подключения к консоли ОС по протоколу SSH. [Скачать]
  • Transmission Remote GUI — графический клиент, для удаленного управления transmission GUI. [Скачать]

P.s.
Если нужно, могу написать инструкцию по установке и настройки samba, а также использованию программ WinSCP и PuTTy.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Создание автономного робота Frank. Часть вторая



Прошло немного времени и у меня значительный прогресс. Если вы не читали предысторию — добро пожаловать в «Создание автономного робота Frank. Часть первая» .

Итак, в первой части я собрал платформу на базе Lego Technic и серво-моторов HiTech. Угробив единственный шилд для прототипирования для Arduino, я ждал, когда мне прийдет замена, плюс новый припой, взамен экологически чистого, который у меня был — без содержания свинца. Так же, у меня в распоряжение была пара XBee для беспроводной связи, с которой необходимо было разобраться и Arduino Due, с которой хотелось поэкспериментировать.



Оказывается, припоем без содержания свинца очень сложно паять, поэтому я заказал другой S-Sn60Pb39Cu2 2.5% Flux производства фирмы Felder. Разница просто потрясающая. Он сразу плавится и отлично ложится на контакты. Это ускорило создание платы во много раз.

Попорядку. Сначала, я сделал свой шилд для управления серво-моторами. Эксперименты с breadboard'ом, конечно, обязательны, чтобы убедиться, что все работает, но выглядит это всегда отвратительно. Для того, чтобы спаять плату, я заказал макетную плату от DFRobot для Arduino Mega, которая прекрасно подошла к Arduino Due. Для управления серво-моторами, надо соединить желтый провод мотора с PWM выходами Arduino через резистор. Надо заметить, что на Arduino Due 12 PWM выходов, что позволяет подключить достаточно много серво-моторов без дополнительных контролеров. На практике, конечно, это надо проверить. Возможно, что на плате не хватит таймеров, чтобы плавно управлять 12 моторами. Плюс и землю надо подсоединить к батареи и объединить землю батареи с землей от Arduino. Об этом, я подробнее писал в предыдущей статье. Плата получилось достаточно чистой и на ней осталось еще много место для других компонентов — например XBee.



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



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

В комплекте с XBee идут две маленькие платы, куда втыкаются беспроводные . Обе платы можно подключить к Arduino, предварительно припаяв лапки и используя макетную плату. У одной из плат есть USB выход (USB-to-Serial).



Так как я планировал взаимодействие и информации между Фрэнком и моим лаптопом, я начал с написания простой программы для общения с XBee через серийный интерфейс. Для этого я скачал последнюю версию Qt (5.1), в которой появился класс QSerialPort, позволяющий общаться с внешними устройствами через серийный порт. Выглядит программа пока как терминал, но в будущем я ее расширю для полного управления Фрэнком через XBee, подключенному к моему компьютеру. Все, что программа делает на данный момент — это посылает и принимает сообщения по серийному порту, которые надо вводить вручную.



Исходный код Так как написано все используя Qt, то работать должно на любом компьютере. Для компиляции необходимо Qt5.1. Проектный файл был сгенерирован QtCreator'ом.

Для начала, необходимо определить как называется XBee, подключенный к компьютеру. Для этого смотрим на список устройств в папке /dev и ищем что-то похожее на tty.usbserial-A9014B88 (так оно называется у меня). В коде меняем строчку «port = new QSerialPort(»usbserial-A9014B88");" на ваше название устройства (без «tty.»).

Если до этого вы сами не конфигурировали XBee, то необходимо поменять «port->setBaudRate(19200);» на 9600 или просто закомментить эту строчку, так как эта скорость по умолчанию прописана в устройстве. Далее запускаем программу, подключив первый модуль и вводим "+++". Три плюса «будят» устройство для дальнейших команд. В ответ вы должны получить «ОК», что отобразится в окне терминала. Через некоторое время (я так и не понял через какое) устройство уходит в спящий режим, так что не затягивайте с остальными командами. Для того, чтобы его снова разбудить, отошлите опять три плюса.

Далее посылаем конфигурацию в первый модуль. «ATID4000,DH0,DL1,MY0,BD4,WR,CN». Это меняет его ID на 4000 (может быть любое число), скорость общения на 19200 и его адрес на «0». Чтобы два устройства общались между собой их ID должен совпадать, а у одного устройства адрес должен быть «0», а у другого «1». После того, как вы послали эту команду, вам должно обратно прийти 7 «ОК» (или около того). Если что-то прошло не так то одно из «ОК» будет «ERROR».

Теперь мы можем вытащить чип из платы и поставить туда второй чип, предварительно отключив плату от компьютера. Повторив все те же команды, за исключением того, что MY0 должно быть MY1 «ATID4000,DH0,DL1,MY1,BD4,WR,CN». Не забудьте, что теперь оба устройства работают на чистоте 19200. Поэтому, при дальнейшем подключение в исходном коде программы надо надо указать эту скорость при подключение — «port->setBaudRate(19200);».

Теперь осталось подключить одно устройство к компьютеру (можете просто оставить то, которое подключено уже), а второе к Arduino. Я опять прибегну к макетной плате, но скорее всего, сегодня припаяю XBee к своему макетному шилду.

Подключение достаточно простое — необходимо соединить VSS с землей Arduino, VCC с 3,3V, DOUT с RX(0 порт на Arduino Due), а DIN с TX(1 порт). На других платах, это могут быть другие порты — просто найдите RX и TX (серийный интерфейс). Теперь надо сделать так, чтобы они посылали друг-другу сообщения.

Опять все оказалось не так просто. SofwareSerial еще не портировали на ArduinoDue — значит использовать можно только хардверный интерфейс, а большинство примеров в интернете, просто не работают. Факт того, что у меня XBee Series1, уменьшил количество примеров, доступных в интернете до минимума. Очень сильно помогла вот эта библиотека. Если у вас Arduino Due, то необходимо скачать «xbee-arduino-0.3.zip», так как версия 0.4 работает через SoftwareSerial. Устанавливаем библиотеку в Arduino (Sketch->Import Library->Add Library) и указываем папку, в которой лежит то, что вы скачали и разархивировали. После этого нажмите (Sketch->Import Library->XBee), и у вас появится строчка "#include <XBee.h>".

Теперь мы можем загрузить вот такой скетч в Arduino.

<code>#include <XBee.h>

// XBEE Code
XBee xbee = XBee();
unsigned long start = millis();
uint8_t payload[] = { 0, 0 };
Tx16Request tx = Tx16Request(0x4000, payload, sizeof(payload));


void setup() {
  // XBee Code
  Serial.begin(19200);
  xbee.setSerial(Serial);
}

void loop() {
  // XBee Code 
  if (millis() - start > 15000) { // Wait for boot and connection to establish
    xbee.send(tx);
  }
  delay(1000);
}
</code>

uint8_t payload[] = { 0, 0 };
— это массив данных, который XBee будет посылать.

Tx16Request tx = Tx16Request(0x4000, payload, sizeof(payload));
— Это запрос на отправку информации. Обратите внимание на 0x4000 — это значение должно соответствовать ID, который мы задали раньше, при настройки пары XBee.

Все, что он будет делать, это посылать два символа с ASCII кодом «0» на другой XBee. Запустив iFrank, можете увидеть, как пустые символы появляются в окне терминала. Это конечно не так интересно, но цель была проверить наличие связи между модулями. К следующий статье я надеюсь разобраться с камерой, обменом информацией между компьютером и Arduino, солнечными батареями, а так же написать управление на Qt.

В сборе сейчас все выглядит вот так:



Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Обзор Highscreen Omega Prime XL



Добрый день. Когда я получил свой Highscreen Prime XL для теста, я не знал, что бренд Highscreen является русским.

Для меня это стало сюрпризом, поэтому я с большим энтузиазмом пригляделся к новинке и, не совру, прибавил куда больше оптимизма в этом обзоре. Мне, все-таки, надоело винить нас, Россию, во всем, что можно: смотреть на «убийцу iPhone с двумя экранами»… пусть лучше мы начнем с бизнес-плана по зарабатыванию денег, который называется Highscreen, но в конечном итоге это может стать Xiaomi- или ZTE-2. В любом случае этот бренд наш, и мне интересно его поддержать.

Оптимистичное, хвалебное видео:


Технические характеристики:

– Qualcomm MSM8225Q, 4 ядра, 1.2 ГГц
– 1 ГБ ОЗУ
– 4 ГБ встроенной памяти
– Разъем карт памяти micro-SD (до 32 ГБ)
– Дисплей TFT IPS, 5.3 дюйма, 540х960 точек
– Камеры: 2 Мп + 8 Мп
– Две SIM-карты
– Аккумулятор, емкостью 2800 мАч

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



Спереди Prime XL покрывает действительно закаленное стекло, а не стекла и пластмассы.



Стоит также упомянуть, что в комплекте с Highscreen Prime идут две сменные панели. Одна матовая ярко-салатовая, другая глянцевая белая. Оригинальный черный корпус также матовый с покрытием софт-тач.



Печаль вызывает лишь то, что находится под этим самым стеклом, а именно 5.3-дюймовый экран с разрешением 540x960 и не очень хорошими углами обзора. Это действительно недостаточное разрешение и это действительно минус. Рассуждать на тему того, как можно «забыть/не смотреть» про/на это я не собираюсь, такой недуг ни чем не скрыть и это факт.



А теперь перейдем к плюсам. Во-первых, под крышкой устройства скрываются три разъема: один для MicroSD и два под MiniSIM. Стоит учитывать тот факт, что когда вам звонят на одну симку – другая перестает функционировать, так как модуль связи здесь один. Кроме этого, 3G-связь может работать также только на одной из SIM-карт.

Примечание: внутренняя память Prime XL – 4 ГБ, 1.5-2 из которых доступно. Дополнительной карты памяти в комплекте нет. Ее нужно покупать отдельно.



Внутри Prime XL установлен аккумулятор, емкостью 2800 мАч. Хватает телефона при средне-активном использовании на 2 дня. При большой загруженности смартфон вытягивает день. Если сравнивать с моим Nexus 4, то Prime XL хватает ровно в два раза больше.

Камеры





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



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

Тест AnTuTu



Highscreen Omega Prime XL стоит около 10 тысяч рублей.



Я думаю, что для 5-дюймового смартфона с двумя SIM, со сменными панелями в комплекте, с невероятно качественной сборкой… для эконом-класса – 10000 рублей это вполне оправданная и приемлемая цена. Еще раз повторюсь, сказав, что мне нравится писать и наблюдать за развитием российского телефоностроения, желаю бренду Highscreen скорейшего становления и захвата рынка. Почему бы и нет?

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


To GIF or not to GIF?

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




Известно, что юмор замедляет процессы старения, а смех продлевает жизнь, именно поэтому нам столь приятно делать iFunny, который ежедневно дарит улыбки и хорошее настроение более, чем 4 миллионам пользователей (в данный момент, к сожалению или счастью, по большей части из США). Мы стремимся стать самым удобным fun-браузером в мире, а также местом, где рождается лучший юмор. В сутки наши пользователи загружают более 250 000 работ.

До недавнего времени мы раздавали около 150TB статики в сутки, но с добавлением анимации в проект получили прирост количества загружаемого контента на 17% и увеличение ежесуточного трафика до 750TB.

GIF

Так сложилось, что в настоящее время в GIF кодируют самые интересные нарезки из юмористических (и не очень) видеороликов, что печально отражается на объеме результирующих файлов. По нашим ощущениям, средний размер GIF-анимации в современном интернете составляет порядка 5Mb. Логичный вопрос, которым мы задались при разработке — сможем ли мы как-то оптимизировать анимацию на серверной стороне, чтобы уменьшить её объём?

Проведя ряд экспериментов с различными анимированными файлами и алгоритмами оптимизации (Basic Frame Optimization, Transparency Optimization), мы пришли к выводу, что выигрыш от оптимизации для большей части изображений оказался совсем небольшим, порядка 10-20%. Более того, если GIF-анимация была уже неплохо оптимизирована её автором, то при автоматическом подходе мы могли получить противоположный эффект.

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

Релиз версии с GIF

Если с реализацией поддержки GIF на стороне сервера и в iOS-клиенте было всё довольно просто, то на Android-клиенте нам пришлось прибегнуть к инструментам бородатых джедаев — libgif + JNI, что только раззадорило нас.

Как только все было закончено, мы прошли проверку цензоров в App Store, залили приложение в Google Play и запустились… И сразу по итогам первого дня увидели резкий скачок просмотров контента и, соответственно, трафика. В первые 24 часа трафик вырос в 6 раз!



Суммарно за полмесяца объем раздаваемого трафика возрос на 200% и в июне, благодаря запуску анимации в iFunny, мы раздали 4.75 Петабайта! Увеличение активности аудитории, безусловно, не может не радовать, но так ли все оказалось хорошо в итоге?
Мы были готовы к определенному количеству GIF-анимации в iFunny, но та , которую мы получили в первые несколько суток, дала нам понять, что мы недобитые оптимисты: реальное количество загружаемой GIF-анимации в сутки превышало ожидаемое в 5 раз. Вкупе с массивными 3-4-мегабайтными GIF, идущими через каждые 3-5 статичных изображений, мы получили сервис, которым можно было пользоваться только через WiFi. Даже пользователям с безлимитным 3G приходилось туго: анимация грузилась долго, а из-за активной работы 3G-модуля девайс сильно разогревался и убивалась батарейка.

Нужно что-то делать...

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

Исходя из вышесказанного, мы решили попробовать отказаться от GIF в пользу какого-нибудь подходящего для воспроизведения коротких анимированных роликов видеоформата. В таком случае, необходимо было найти подходящий формат кодирования. Были рассмотрены стандарты кодирования h.263, h.264, а также видеокодек vp8 в контейнере WebM.

Провели тесты рекодирования GIF в видео, и замаячил свет в конце тоннеля: размер результирующих видеороликов получался в 2-10 раз меньше, чем GIF-исходник!

Осталось определиться с кодеком. Использование кодека-пенсионера — h.263 давало ужасную результирующую картинку и противоречило нашим моральным нормам, поэтому его мы отмели первым.
h.264 — хороший кодек, однако связываться с охраняемыми патентами технологиями нам не хотелось, да и результирующий размер файла оказывался довольно большим: на 20-40% больше, чем при кодировании того же фрагмента в vp8. Поэтому мы решили остановиться на vp8.

Дополнительным аргументом при выборе vp8 также послужило то, что Google активно внедряет и использует его на YouTube, и в настоящий момент разрабатывается улучшенный формат VP9, что позволяет судить об успешности и перспективности всего проекта в целом.

Для конвертации из GIF в WebM используем сборку ffmpeg с поддержкой GIF-декодера и vp8-энкодера. Сам процесс конвертации проходит без особых замечаний и довольно быстро, но сразу же сталкиваемся с проблемой в результирующем видеоролике. Возьмем такую GIF-анимацию, например:



Обратите внимание, у последнего кадра есть задержка в 2 секунды, после чего анимация проигрывается заново. В полученном WebM-файле эта задержка куда-то волшебным образом исчезает, и последний кадр “проскакивает”. Анализ прочего контента показал, что задержка после последнего кадра у анимации убирается всегда, что для нас является довольно большой проблемой, ведь мы хотим, чтобы пользователи в приложении вообще не видели разницу между GIF и видеороликом. Проблему решили, но таким костылём, что до сих пор краснеем от стыда: к конвертируемой GIF добавляем дубликат последнего фрейма.
В рядах мобильных разработчиков в это время царил хардкор: собрали libvpx под нужные платформы, написали обёртку-плеер на Си и вуаля.

Релиз версии с WebM

После релиза версии, где пользователям вместо GIF-анимации мы стали проигрывать короткие видеоролики, стало ясно, что проделанная работа принесла свои плоды: расход трафика за одну сессию снизился с неадекватных 50-100Mb до вполне комфортных 7-20Mb, девайсы стали меньше греться и убивать батарейку, а самое главное, пользователи стали видеть контент чаще, чем его прелоадер.

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



Переход с GIF на WebM позволил сократить объемы раздаваемого трафика на 30% и снизить CDN-расходы примерно на $50 000 в месяц.

Выводы

Формат GIF87, созданный более 20 лет назад, по задумке автора должен был использоваться для передачи растровых изображений по сети, а модификация GIF89 позволяла использовать изображения с прозрачностью и хранить набор простых слайдов с определенной задержкой — анимацию.

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

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

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

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Верстка Android макетов без боли

Разрабатывать интерфейс Android приложений — непростая задача. Приходится учитывать разнообразие разрешений и плотностей пикселей (DPI). Под катом практические советы о верстке макетов дизайна Android приложений в Layout, который совпадает с макетом на одном устройстве а на остальных растягивается без явных нарушений дизайна: выхода шрифтов за границы; огромных пустых мест и других артефактов.




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

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

Чтобы упорядочить хаос мы пришли к следующему алгоритму верстки. Макеты рисуются и верстаются под любой флагманский full-hd телефон. На остальных красиво адаптируются. Готовое приложение проверяет дизайнер на популярных моделях смартфонов. Метод работает для всех телефонов, для планшетов (>6.5 дюймов) требуются отдельные макеты и верстка.

Под рукой у меня только Nexus 4 возьмем его характеристики экрана для примера.

Макеты ненастоящего приложения-портфолио которые будем верстать (полноразмерные по клику).


Layout

Основную верстку делаем через вложенные LinearLayout. Размеры элементов и блоков в пикселях переносим с макета в weight и weightSum соответственно. Отступы верстаем FrameLayout или в нужных местах добавляем Gravity.

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


<code class="xml"><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- 488 = 768 - 40 (левый отступ) - 40 (правый отступ) - 200 (ширина картинки) -->
    <LinearLayout
        android:id="@+id/appLstItemLayout"
        android:orientation="horizontal"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:gravity="center"
        android:weightSum="488" 
        android:background="@drawable/bg_item">

        <ImageView
            android:id="@+id/appImg"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:adjustViewBounds="true"
            android:src="@drawable/square"/>

        <FrameLayout
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_weight="20"/>

        <!-- 130 = высота ячейки - 40 (высота звездочек) -->
        <LinearLayout
            android:orientation="vertical"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="428"
            android:gravity="center"
            android:weightSum="130">

            <FrameLayout
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:layout_weight="55"/>

            <TextView
                android:id="@+id/titleTxt"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="bottom"/>

            <FrameLayout
                    android:layout_width="0dp"
                    android:layout_height="0dp"
                    android:layout_weight="10"/>

            <ru.touchin.MySimpleAndAwesomeRatingBar
                android:id="@+id/appRatingBar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"/>

            <FrameLayout
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:layout_weight="25"/>
        </LinearLayout>
    </LinearLayout>
</FrameLayout></code>
Дальше нам потребуется много DisplayMetrics-магии, напишем для него static helper.

<code class="java">public class S {
	private static final int ORIGINAL_VIEW_WIDTH = 768;
	private static final int ORIGINAL_VIEW_HEIGHT = 1184;
	private static final int ORIGINAL_VIEW_DIAGONAL = calcDiagonal(ORIGINAL_VIEW_WIDTH, ORIGINAL_VIEW_HEIGHT);

	private static int mWidth;
	private static int mHeight;
	private static int mDiagonal;
	private static float mDensity;

	static {
    	DisplayMetrics metrics = TouchinApp.getContext().getResources().getDisplayMetrics();
    	mWidth = metrics.widthPixels;
    	mHeight = metrics.heightPixels;
    	mDiagonal = calcDiagonal(mWidth, mHeight);
    	mDensity = metrics.density;
	}

	public static int hScale(int value){
    	return (int)Math.round(value * mWidth / (float) ORIGINAL_VIEW_WIDTH);
	}

	public static int vScale(int value){
    	return (int)Math.round(value * mHeight / (float) ORIGINAL_VIEW_HEIGHT);
	}

	public static  int dScale(int value){
    	return (int)Math.round(value * mDiagonal / (float) ORIGINAL_VIEW_DIAGONAL);
	}

	public static  int pxFromDp(int dp){
    	return (int)Math.round(dp * mDensity);
	}

	private static int calcDiagonal(int width, int height){
    	return (int)Math.round(Math.sqrt(width * width + height * height));
	}
}</code>
1184 это высота Nexus 4 без кнопок, 768 — ширина. Эти значения используются, чтобы выяснить во сколько раз высота и ширина устройства, на котором запущено приложение, отличаются от эталонного.

ScrollView и List
Подход с weightSum не примемим к прокручивающимся элементам, их внутренний размер вдоль прокрутки ничем не ограничен. Для верстки ScrollView и List нам потребуется задать их размеры в коде (130 — высота элемента списка).

<code class="java">if (view == null) {
    view = mInflater.inflate(R.layout.item_app_list, viewGroup, false);
    view.setLayoutParams(new AbsListView.LayoutParams (ViewGroup.LayoutParams.MATCH_PARENT, S.dScale(130)));
 }</code>
И дальше можно применять трюк с weightSum.

Картинки

Размер иконок приложений задается в коде:

<code class="java">view.findViewById(R.id.appImg).setLayoutParams(new LinearLayout.LayoutParams(S.dScale(240) - S.pxFromDp(20), S.dScale(240) - S.pxFromDp(20)));</code>
Где 240 высота элемента списка, 20 высота отступа сверху и снизу.

Шрифты

Андроид не предоставляет единицу измерения пропорциональную размеру экрана. Размеры шрифтов рассчитываем на основании диагонали устройства:
<code class="java">textSizePx = originalTextSizePx * (deviceDiagonalPx / originalDeviceDiagonalPx )</code>
Да, размеры шрифта придется задавать в коде (36 размер шрифта в пикселях на оригинальном макете).
<code class="java">titleTxt.setTextSize(TypedValue.COMPLEX_UNIT_PX, S.dScale(36));</code>

Советы по работе с графикой

1. Используйте Nine-patch везде где возможно, где невозможно — перерисуйте дизайн.
2. Простые элементы рисуйте с помощью Shape
3. Избегайте масштабирования изображений в runtime

Nine-patch это графический ресурс содержащий в себе мета-информацию о том как он должен растягиваться. Подробнее в документации Android или на Хабре.

Nine-patch нужно нарезать под все dpi: ldpi mdpi tvdpi hdpi, xhdpi, xxhdpi. Растягивание ресурсов во время работы приложения это плохо, а растягивание Nine-Patch приводит к неожиданным артефактам. Ни в коем случае не задавайте в Nine-patch отступы, они оформляются отдельными элементами layout, чтобы растягиваться пропорционально контенту.



Shape

Если ресурс легко раскладывается на простые геометрические фигуры и градиенты лучше вместо нарезки использовать xml-shape. Для примера нарисуем фон рамку вокруг проекта в списке, которую мы выше нарезали как Nine-patch.



<code class="xml"><layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
	<!-- "shadow" -->
	<item>
    	<shape android:shape="rectangle" >
        	<corners android:radius="5px" />
        	<solid android:color="#08000000"/>
    	</shape>
	</item>
	<item
    	android:bottom="1px"
    	android:right="1px"
    	android:left="1px"
    	android:top="1px">
    	<shape android:shape="rectangle" >
        	<corners android:radius="4px" />
        	<solid android:color="#10000000"/>
    	</shape>
	</item>
	<item
    	android:bottom="2px"
    	android:right="2px"
    	android:left="2px"
    	android:top="2px">
    	<shape android:shape="rectangle" >
        	<corners android:radius="3px" />
        	<solid android:color="#10000000"/>
    	</shape>
	</item>
	<item
    	android:bottom="3px"
    	android:right="3px"
    	android:left="3px"
    	android:top="3px">
    	<shape android:shape="rectangle">
        	<corners android:radius="2px" />
        	<solid android:color="#ffffff"/>
    	</shape>
	</item>
</layer-list></code>

Картинки
Масштабирование графики силами Android трудоемкая и затратная по памяти операция. Картинки внутри Android обрабатываются как bitmap. Например, наш логотип в размере 500x500 со сплешскрина распакуется в bitmap размером 1мб (4 байта на пиксель), при масштабировании создается еще один bitmap, скажем в 500кб. Или 1,5мб из доступных 24мб на процесс. Мы не раз сталкивались с нехваткой памяти в богатых на графику проектах.

Поэтому картинки которые нельзя описать ни Nine-patch ни Shape я предлагаю поставлять в приложении как огромный ресурс в папке nodpi и при первом запуске масштабировать изображение до нужного размера и кешировать результат. Это позволит нам ускорить работу приложения (не считая первого запуска) и уменьшить потребление памяти.

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

<code>http://<secret_domain>/media/img/movies/vposter/plain/22741680/<любая ширина px>_<любая высота px>.jpg</code>

P.S. советы придуманы и основа поста написаны нашим Android-гуру Лешей, огромное ему спасибо!

А как вы рекомендуете верстать макеты под Android? Сколько макетов рисует дизайнер? Как обращаетесь с графическими ресурсами?


Подписывайтесь на наш хабра-блог (кнопка справа вверху). Каждый четверг интересные статьи о мобильной разработке, маркетинге и бизнесе мобильной студии. Следующая статья (5 сентября) «C# async на iOS и Android»

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Летим на Мальдивы

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

Мечтает…

Мальдивы. Жемчужное ожерелье на лике Земли. Тысяча белых островов в лазурном океане. Ходят слухи, что Мальдивских островов лет так через 30 не станет, уйдут под воду, как Атлантида. Но все-таки это райские острова, с удивительной фауной, на которые стоит хоть раз в жизни посмотреть воочию.


Но не улетает.

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

А хочется.

И, что делать? Так и продолжать мечтать мечты?

Руководители с опытом ответят: «Да тут все просто! Надо делегировать часть своей работы подчиненным».

Просто. Надо. Но не всегда возможно.

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

Руководителем проекта становятся по-разному.

Самый трудный случай – это, когда вас, никому неизвестного в команде человека, назначает высокое начальство. Ни доверия, ни признания профессионализма. А проект продвигать надо. В этом случае у вас есть только одна возможная стратегия – директивное управление.

Паттерн 1. Директивное управление. Жесткое назначение работ, строгий контроль сроков и результатов.
Другой вариант. О вас, таки, слышали в команде. Даже возможно ознакомились с вашим резюме, в котором отражен богатый опыт реализации вами проектов, для заказчиков из списка топ 500 компаний Forbes. Так что, скорее всего ваш профессионализм не будет подвергаться сомнению. Однако, доверия не ждите. В резюме не принято писать, сколько крови и трупов программистов осталось на вашем карьерном пути. Вот и команда об этом не в курсе. Чтобы завоевать доверие, необходимо активно привлекать участников коллектива к выработке и принятию решений.

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

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

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

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

Помним, что ответственность не делегируется. За все «косяки» в проекте должны отвечать всегда вы.

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

ЗЫ. Про теорию ситуационного лидерства знаю. Похоже. Но мой пост о другом.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Обзор новых IP АТС от Grandstream



Мне попала в руки одна из новых IP АТС от Grandsteream UCM6108 и я спешу поделиться своими впечатлениями. Сразу скажу, что это уникальный по способности к конкуренции продукт, так как внутри в основе код уже достаточно развитой open source платформы Asterisk. Это дает возможность производителю вообще отказаться от такого понятия как лицензирование портов и функционала, а количество телефонных функций уже с первыми прошивками очень большой. За доступную цену, которая, кстати сказать, ниже цены на сервер или компьютер, на котором можно поднять бесплатную IP АТС, пользователь получает готовую к работе железку, весь имеющийся функционал без закупки дополнительных лицензий и простоту конфигурирования. Все манипуляции с АТС происходят только через web-интерфейс, все остальные способы поломать обслуживать АТС закрыты для пользователя. Web интерфейс, кстати, очень неплохо русифицирован, и, как оказалось, его более чем достаточно для работы с продуктом.

Вот, собственно, полностью технические характеристики UCM www.grandstream.com/products/ucm_series/ucm61xx/marketing/ucm61xx_brochure_russian.pdf

Основные характеристики, то, что можно позволить на этом сервере, приведу здесь:
До 500 ip абонентов
До 60 одновременных вызовов
До 6 одновременных аудио конференций и до 32 участников
Запись разговоров, запись конференции
IVR до 5 уровней, голосовая почта, голосовые подсказки,
2 FXS и 8 FXO портов

Железо

В коробке с UCM1608 поставляется универсальный блок питания 12В 1,5А, ушки для крепления в 19” стойку и Ethernet кабель. Корпус в глубину не более 20 см. Сзади разъем для блока питания, LAN и винтик для подключения заземления. Спереди разъемы USB, SD, 2 FXS и 8 FXO портов, светодиоды состояния и жк дисплей для просмотра информации.


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



Внутренняя память около 100Mb отводится на конфигурацию и 3Gb на хранение данных – CDR, запись разговоров, сообщений голосовой почты и т.д. Для этих же целей можно использовать SD карточку. USB удобно использовать для резервного хранения конфигураций.


Принцип Zero Cоnfig

Удобнее всего подключать к АТС собственные SIP терминалы Grandstream с помощью принципа Zero Configuration, предварительно создав телефоны в разделе Extensions. Автоматически определяется тип включенного в сеть устройства, его версия прошивки, MAC и IP адрес, затем автоматически назначается ему номер из указанного диапазона. Затем телефону дается указание получить конфигурацию по HTTPS и перегрузиться. Все. В итоге, через некоторое время все найденные телефоны зарегистрированы и готовы к работе. Можно также указать диапазон сети, где обнаруживать телефоны или указать только один ip адрес. Также можно назначать номера на нужные телефоны вручную.


В планах у разработчиков создать поддержку Zero Configuration и для ip телефонов других производителей.

Интересные функции

Функционал UCM очень богат, поэтому я планирую подробно перечислить и сделать анализ всех функций в отдельном обзоре, хотя для людей из мира Asterisk они все знакомы и не новы. Для них скажу, что за основу взята версия астериска 1.8. Здесь же упомяну только о некоторых функциях, которые показались особо любопытными мне, как человеку более знакомому с функционалом других популярных на рынке производителей. В мире традиционных офисных атс некоторых функций просто нет, а некоторые могут стоить дополнительно больших денег. Поэтому, получается, то, что приятно удивило меня, и есть то, что выгодно отличает этот продукт на фоне имеющихся на рынке традиционных офисных и учрежденческих АТС.

Распознавание кодов функций во время разговора

Заинтересовал необычный принцип набора функциональных кодов во время разговора. Например, чтобы перевести звонок, не обязательна специальная кнопка Transfer в ip телефонах, либо flash в аналоговых. Во время разговора просто нужно набрать код трансфера (по умолчанию *2). АТС автоматически распознает, что это функциональный код, а не DTMF сигнал, и на дальнем конце этот сигнал не услышат. Вы же услышите голосовое подтверждение «перевод…» и предложение набрать номер направления. Если все же возникнет желание передать последовательность *2 как dtmf код, необходимо после набора звездочки или решетки не забыть сделать небольшую паузу и затем набирать дальше. По такому принципу работает целый ряд функциональных кодов. Например, чтобы записать свой разговор, пользователь всего лишь во время разговора должен набрать *3. На дальнем конце нажатие этих клавиш не услышат.

Речевые сообщения

Голосовые подтверждения, стандартные голосовое меню в голосовой почте и в автооператоре и т.д., на многих языках, включая русский, уже готовые, можно загрузить в UCM как один .gz файл, используя web интерфейс в один клик. Есть возможность записать свои речевые сообщения вместо стандартных и скомпилировать свой файл речевых сообщений. Инструкция есть.



Группы звонка, пейджинг и интерком, очереди вызовов

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



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



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


Парковка и пейджинг на аппараты

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

CDR и запись разговоров

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



Там же можно прослушать или скачать разговор, если он был записан:



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


Конференция

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



Fax и голосовая почта в e-mail

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


Кстати, голосовая почта также может отсылаться на email пользователя:


Обслуживание

WEB интерфейс администратора UCM является достаточно удобным инструментом и для выявления и диагностики проблем в процессе эксплуатации и помощи в настройке. На странице состояния АТС, например, сведены статусы всех аналоговых интерфейсов, телефонов, SIP транков, очередей звонков и конференций:


Есть возможность также воспользоваться командами ping, tracerout, снять трасировки:




SIP NAT

Многим, наверное, известны проблемы, возникающие, когда ваша АТС находится за NAT. В этом случае невозможно подключиться по SIP снаружи, потому что простой трансляции адресов не достаточно для прохождения звонков. Необходим еще один элемент сети, который бы умел подменять адреса на уровне сессий в самой сигнализации SIP, например Session Border Controller или SIP Application Layer Gateway. Здесь эта функция уже встроенная и называется SIP NAT:



LDAP

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


Недоработки и детские болезни

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

Из того что пока не хватает я бы отметил:
• Нет возможности манипулировать номер did входящего звонка, только обрезать первые цифры. Можно решить эту задачу созданием групп звонков с нужными номерами и включить в них нужные телефоны, но все равно это может ограничивать номерной план.
• Нет возможности манипулировать clid входящего звонка для удобного обратного вызова.
• Нет возможности назначать разные правила набора на разные телефоны, есть только разграничение по уровню разрешений (Международный, междугородний, местный и внутренний)
• В функции записи разговора нет голосового подтверждения, отсюда нет уверенности, что разговор действительно пишется.
• Нет возможности подставлять разный clid для внутренних телефонов при выходе на разные направления. Создание did таблиц для разных направлений, как меня заверили, уже поставлено в задачу разработчикам.
• Нет отдельного web интерфейса для администраторов конференций. Управление конференциями можно только осуществлять пока из общего окна администратора UCM.
В создании новых функций для UCM можно поучаствовать и самому, написав запрос в на официальном сайте Грандстрима.

Итоги

Насколько бесплатны современные IP АТС с открытым кодом? Необходим сервер, необходимы шлюзы для подключения телефонии и, наконец, необходимо заплатить специалистам, которые бы все собрали, подняли и продолжали поддерживать эту достаточно не простую систему. А вот у Grandstream новая линейка IP АТС вышла проще, удобнее и поэтому, получается, еще бесплатнее. Судите сами: младшая модель в этой линейке, небольшая коробочка, может подключить до 500 абонентов, 30 одновременных звонков, собирать в конференцию до 25 участников, имеет 2 FXS и 2 FXO порта, не требует никаких дополнительных лицензий – и стоит менее $400. Это меньше, чем может стоить только сервер, не говоря уже про шлюзы и затраты на специалистов. Все усилия разработчиков направлены на простоту конфигурирования через web интерфейс, поэтому с АТС может разобраться любой системный администратор. За основу взят Asterisk, поэтому функционал АТС уже сейчас богаче, чем у большинства брендовых АТС и будет расширяться с каждой новой прошивкой.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Поправки к закону о блокировке ресурсов

Добрый день, хабрасообщество.

Буквально сегодня обнаружил внесенный законопроект № 336400-6 «О внесении изменений в отдельные законодательные акты Российской Федерации по вопросам защиты прав субъектов деятельности в сфере использования информационно-телекоммуникационных технологий».

Я смог осилить не все поправки, вносимые законопроектом, но исходя из пояснительной записки, направленной вместе с проектом в аппарат Госдумы, речь идет об отмене «досудебной» блокировки сайтов по велению левой пятки, по обращению правоторговцев:

Следует отметить, что серьезную обеспокоенность принятием «сырого» Закона выразили такие гиганты Интернет-индустрии, как Яндекс и Google, РАЭК, Mail.ru Group, Афиша-Рамблер-СУП, RU-CENTER, Хостинг-Центр, OZON.RU, а также представители общественных организаций, ассоциаций, фондов и порталов: Фонд содействия развитию технологий и инфраструктуры Интернета, Ассоциация интернет-издателей, Ассоциация пользователей интернета, Пиратская партия России, РосКомСвобода, ряд электронных библиотек, СМИ, файлообменных сервисов и трекеров.
Общественную инициативу об отмене Закона подписали более 100 тысяч граждан России.
Численность граждан, не поддерживающих данный закон, составляет десятки миллионов пользователей интернета в России, владельцев сайтов и порталов, представителей IT-бизнеса, СМИ, авторов, дизайнеров, музыкантов, учёных и людей разных профессий, использующих Интернет каждый день.
Есть все основания полагать, что принятый Закон повлечет снижение достигнутого уровня развития Интернет-системы. Сегодня российская
Интернет-индустрия занимает лидирующие позиции на международной арене, в частности — четвертое место по объему инвестиций и первое место по количеству пользователей в Европе. На Интернет и связанные с ним экосистемы приходится 4,62 % ВВП России; прирост в этой сфере составляет до 30% в год.
Исходя из изложенного авторы настоящего законопроекта предлагают признать Федеральный закон от 2 июля 2013 года № 187-ФЗ «О внесении изменений в отдельные законодательные акты Российской Федерации по вопросам защиты интеллектуальных прав в информационно-телекоммуникационных сетях» и все внесенные им в российское законодательство изменения утратившими силу.
Только после этого можно будет не спеша, с участием всех сторон и проведением всенародного обсуждения, с учетом мнения экспертов и других профессионалов разработать и принять закон, направленный на защиту интеллектуальных прав в информационно-телекоммуникационных сетях.

P.S. Разумеется, далеко не факт, что этот проект будет принят.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Как себя чувствует RADIUS?

Сегодняшний день начался с неожиданного. Один из наших Заказчиков сообщил, что он считает, что RADIUS сервер не справляется с работой, поскольку NAS отсылает большое количество запросов повторно. Так как это достаточно серьезное обвинение, его следовало немедленно проверить. Описанию того как это сделать, посвящена эта статья (материал ориентирован на начинающих разработчиков и системных администраторов).

Первый шаг довольно очевиден. Необходимо получить дамп сетевой активности во время максимальной нагрузки на RADIUS-сервер. Данных 10-15 минутного интервала вполне достаточно для анализа. Для Unix-like систем получить эти данные можно при помощи tcpdump, но поскольку, в нашем случае, RADIUS-сервер работал на Windows-системе, пришлось прибегнуть к помощи Wireshark. Выполнив захват пакетов, Wireshark показал эту замечательную картинку:

image

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

image

Результирующий файл выглядит следующим образом:

<code>+---------+---------------+----------+
10:03:59,092,544   ETHER
|0   |ff|ff|ff|ff|ff|ff|00|0c|29|6b|5a|a3|08|00|45|00|00|e5|b6|15|00|00|80|11|04|d4|c0|a8|7d|ce|c0|a8|7f|ff|00|8a|00|8a|00|d1|ee|a9|11|0e|d1|fb|c0|a8|7d|ce|00|8a|00|bb|00|00|20|46|44|46|41|44|44|43|41|43|41|43|41|43|41|43|41|43|41|43|41|43|41|43|41|43|41|43|41|43|41|43|41|00|20|45|4a|45|4f|46|45|45|46|46|43|43|41|43|41|43|41|43|41|43|41|43|41|43|41|43|41|43|41|43|41|42|4e|00|ff|53|4d|42|25|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|11|00|00|21|00|00|00|00|00|00|00|00|00|e8|03|00|00|00|00|00|00|00|00|21|00|56|00|03|00|01|00|00|00|02|00|32|00|5c|4d|41|49|4c|53|4c|4f|54|5c|42|52|4f|57|53|45|00|01|00|80|fc|0a|00|53|50|33|00|25|03|00|00|00|00|fc|5e|20|03|02|00|05|01|03|12|01|00|0f|01|55|aa|00|

+---------+---------------+----------+
10:03:59,184,049   ETHER
|0   |ff|ff|ff|ff|ff|ff|00|1d|7d|3a|f9|3a|08|06|00|01|08|00|06|04|00|01|00|1d|7d|3a|f9|3a|0a|15|52|44|00|00|00|00|00|00|0a|15|52|41|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|
...
</code>
С этим уже можно работать. Из спецификаций RFC 768, 2865, 2866 нам известны смещения интересующих нас полей (смещения представлены в десятеричной системе счисления, значения — в шестнадцатеричной):

<code>+23 = 11 (UDP)
+36 = 07 14 (RADIUS Destination Port = 1812)
    +42 - (01 = Access Request)
    +43 - ID
+34 = 07 14 (RADIUS Source Port = 1812)
    +42 - (02 = Access Accept; 03 = Access Reject)
    +43 - ID
+36 = 07 15 (RADIUS Destination Port = 1813)
    +42 - (04 = Accounting Request)
    +43 - ID
+34 = 07 14 (RADIUS Source Port = 1812)
    +42 - (05 = Accounting Response)
    +43 - ID
</code>
Обработать данные нам поможет Perl:

Скрипт
<code class="perl">use Time::Local;

my $tm;
my $ln;

my %auth;
my %acco;

my %discarded;
my %accepted;

# Обрабатываем все поступающие строки
while (<>) {
  # Убираем перевод строки
  chomp;
  s/\|0\s+\|//;
  # Регулярным выражением извлекаем время
  if (/^(\d\d):(\d\d):(\d\d),(\d\d\d),\d\d\d/) {
      # Приводим значение времени к количеству миллисекунд с начала эпохи
      # Поскольку дата нас не интересует, берем 01/01/1970
      $tm = timelocal($3, $2, $1, 01, 01, 1970) * 1000 + $4;
  }
  if (/\|/) {
      $ln .= $_;
  } else {
      if ($ln) {
          # Разбиваем строку на байты
          my @packet = split /\|/, $ln;
          # Нас интересуют только UDP-пакеты
          if ($packet[23] eq '11') {
              my $code = $packet[42];
              my $id   = $packet[43];
              # RADIUS Request
              if ($packet[36] eq '07' and 
                 ($packet[37] eq '14' or $packet[37] eq '15')) {
                  # Аккаутинг
                  if ($code eq '04') {
                      # Повтор ID запроса означает потерю соответствующего ответа
                      if (exists($acco{%id})) {
                          $discarded{$code}++;
                      }
                      # Сохраняем время получения запроса
                      $acco{%id} = $tm;
                  # Авторизация
                  } else {
                      if (exists($auth{%id})) {
                          $discarded{$code}++;
                      }
                      $auth{%id} = $tm;
                  }
              }
              # RADIUS Response
              if ($packet[34] eq '07' and 
                 ($packet[35] eq '14' or $packet[35] eq '15')) {
                  # Аккаутинг
                  if ($code eq '05') {
                      if (exists($acco{%id})) {
                          if ($tm - $acco{%id} > 1000) {
                              # Если прошло более 1 секунды, считаем пакет отброшенным
                              $discarded{$code}++;
                          } else {
                              # Иначе увеличиваем количество успешно обработанных пакетов
                              $accepted{$code}++;
                          }
                          delete($acco{%id});
                      }
                  # Авторизация
                  } else {
                      if (exists($auth{%id})) {
                          if ($tm - $auth{%id} > 1000) {
                              $discarded{$code}++;
                          } else {
                              $accepted{$code}++;
                          }
                          delete($auth{%id});
                      }
                  }
              }
          }                      
          $ln = '';
      }
  }
}

# На всякий случай, учитываем ID, для которых не сформирован ответ
while (($id, $tm) = each(%auth)) {
  $discarded{'01'}++;
}

while (($id, $tm) = each(%acco)) {
  $discarded{'04'}++;
}

#Выводим результаты обработки
print "Auth  Accepted: $accepted{'02'}\n";
print "Auth  Rejected: $accepted{'03'}\n";
print "Acco Responsed: $accepted{'05'}\n\n";

print "Auth Request  Discarded: $discarded{'01'}\n";
print "Auth Accept   Discarded: $discarded{'02'}\n";
print "Auth Reject   Discarded: $discarded{'03'}\n";
print "Acco Request  Discarded: $discarded{'04'}\n";
print "Acco Response Discarded: $discarded{'05'}\n";
</code>

Поскольку мы все еще работаем в Windows, bang-комментарий в исходном коде не обязателен (кстати, Perl для Windows можно взять здесь). Для работы со временем, не забываем подключить Time::Local. Скрипт запускаем на выполнение следующей командой:

<code>perl stat.pl dump.txt > dump
</code>
Скрипт работает довольно долго (в основном из-за split-а большого объема данных), но один раз можно и потерпеть. В конечном итоге, формируется следующий результат:

<code>Auth  Accepted: 195
Auth  Rejected: 907
Acco Responsed: 6058

Auth Request  Discarded: 13
Auth Accept   Discarded: 
Auth Reject   Discarded: 
Acco Request  Discarded: 1476
Acco Response Discarded: 
</code>
Здесь мы видим, что за 10 минут было успешно обработано 6058 пакетов аккаунтинга и 1102 пакетов авторизации (из них на 907 запросов был сформирован Reject). Все запросы были обработаны сервером не более чем за 1 секунду. По непонятной причине, NAS отослал 13 повторных запросов авторизации и 1476 запросов аккаунтинга. Возможно это связано с потерями UDP-пакетов при передаче их по сети.

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

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Отказываемся от шаблонных шаблонных параметров

Использовать шаблонные шаблонные параметры С++ довольно сложно. Хочу продемонстрировать силу boost::mpl и показать трюк, позволяющий описывать шаблоны, полностью отказавшись от шаблонных шаблонных параметров.
Продемонстрирую проблему. Есть класс, принимающий тип объекта и тип контейнера для этого объекта.
<code class="cpp">template <typename T, typename Container>
struct A
{
  typedef Container<T> type;
};
</code>
Так писать нельзя, вы должны использовать шаблонные шаблонные параметры, чтобы указать, что
Container
сам по себе является шаблоном.

Правильно написать так:
<code class="cpp">template <typename T, template<typename> class Container>
struct A
{
  typedef Container<T> type;
};
</code>
Использовать так:
<code class="cpp">typedef A<int, std::vector>::type type;
</code>
При первом же использовании мы получим ошибку компиляции. Мы забыли, что std::vector принимает два параметра, один из которых обычно используется по умолчанию. Хорошо, перепишем:
<code class="cpp">template <typename T, template<typename, typename> class Container>
struct A
{
  typedef Container<T, std::allocator<T> > type;
};
</code>
Тут две явные проблемы:
  1. Мы должны заглянуть в реализацию std::vector, выяснить, какой тип аллокатора используется по умолчанию, и тогда использовать его.
  2. Написанный нами шаблон не подойдёт, если у контейнера больше одного шаблонного параметра по умолчанию.
Хотелось бы избежать явного указания типов по умолчанию и сложного синтаксиса шаблонных шаблонных параметров. На помощь приходит приём, основанный на использовании плейсхолдеров из boost::mpl, которые используются для создания лямбда метафункций.

Внешне разница лишь в том, что нужно передавать в наш шаблон не сам шаблон контейнера, а инстанцированный плейсхолдером шаблон контейнера, то есть вместо
<code class="cpp">typedef A<int, std::vector>::type type;
</code>
пишем
<code class="cpp">typedef A<int, std::vector<boost::mpl::_1> >::type type;
</code>
Чтобы инстанцировать инстанцированный плейсхолдером контейнер нужным типом используем boost::mpl::apply:
<code class="cpp">#include <boost/mpl/apply.hpp>
template <typename T, typename Container>
struct A
{
  typedef typename boost::mpl::apply<Container, T>::type type;
};
</code>
Использование этого трюка в реальном программировании поможет упростить некоторые ваши запутанные шаблоны.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


В Госдуму внесли законопроект об отмене «антипиратского» закона



Депутаты от КПРФ: Иван Мельников и Олег Смолин внесли в думу законопроект который призван отменить текущий «антипиратский» закон.

В пояснительной записке, депутаты написали из-за чего они считают данный закон неверным:
  • Нет четких определений практически ничего в законе
  • Имеются очевидные варианты обхода
  • Страдают нормальные сайты которые находятся на том же IP адресе что и спорный ресурс
  • На РОИ инициатива против этого закона набрала 100 000 голосов чуть больше чем за месяц
В дальнейшем, КПРФ предлагает провести всесторонние обсуждения с участием всех сторон для создания действительно нормального законопроекта.

Тем временем: BitTorrent sync стал доступен для iOS



Что будет дальше?


Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста. Проголосовало 4220 человек. Воздержалось 804 человека. Источник: habrahabr.ru,
получено с помощью rss-farm.ru




Ничего не изменится, всё проигнорируют



Закон отменят и НЕ примут новый



Закон отменят и примут другой с правками от экспертов (Провайдеров, хостинг провайдеров и пр)



Закон изменят, расширят и дополнят, все станет еще хуже

[Перевод] Структуры данных, PHP. Часть вторая

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

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

UPD: Добавил сравнение производительности

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

Двоичную кучу (maxheap) можно представить таким образом:

image

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

  1. create – создать пустую кучу.
  2. isEmpty – определить, пуста ли куча или нет.
  3. insert – добавить элемент в кучу.
  4. extract – извлечь и удалить элемент (корень, вершину) из кучи.

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

Правило для удаления элемента из кучи состоит в том, что удалять можно только корневой элемент. Допустим, мы удалили корневой элемент из примера выше (100). После удаления мы останемся с двумя раздельными кучами и нам нужно как-то пересобрать все это в одну отдельную кучу. Легче всего это сделать перемещением последнего узла в корень, однако в таком случае такая куча не будет подходить по основному условию. Такая куча называется semiheap:

image

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

Мы можем реализовать maxheap как массив. Узел в бинарном дереве не может иметь более двух потомков, поэтому для любого количества узлов n бинарная куча будет иметь 2n+1 узел.

Реализуем кучу следующим образом:

<code class="php"><?php
class BinaryHeap
{
    protected $heap;
 
    public function __construct() {
        $this->heap  = array();
    }
 
    public function isEmpty() {
        return empty($this->heap);
    }
 
    public function count() {
        // возвращаем размер кучи
        return count($this->heap) - 1;
    }
 
    public function extract() {
        if ($this->isEmpty()) {
            throw new RunTimeException('Куча пуста!');
        }
 
        // извлечем первый элемент из кучи и присвоим его как корень
        $root = array_shift($this->heap);
 
        if (!$this->isEmpty()) {
            // переместим последний элемент кучи на ее вершину
            // чтобы избавиться от двух разделенных между собой ветвей
            $last = array_pop($this->heap);
            array_unshift($this->heap, $last);
 
            // превратим полукучу в кучу
            $this->adjust(0);
        }
 
        return $root;
    }
 
    public function compare($item1, $item2) {
        if ($item1 === $item2) {
            return 0;
        }
        // обратное сравнение даст нам minheap
        return ($item1 > $item2 ? 1 : -1);
    }
 
    protected function isLeaf($node) {
        // здесь всегда будет 2n + 1 узел в "подкуче"
        return ((2 * $node) + 1) > $this->count();
    }
 
    protected function adjust($root) {
        // спускаемся как можно ниже
        if (!$this->isLeaf($root)) {
            $left  = (2 * $root) + 1; // левый потомок
            $right = (2 * $root) + 2; // правый потомок
             
            $h = $this->heap;
            // если корень меньше своих потомков
            if (
              (isset($h[$left]) &&
                $this->compare($h[$root], $h[$left]) < 0)
              || (isset($h[$right]) &&
                $this->compare($h[$root], $h[$right]) < 0)
            ) {
                // находим старшего потомка
                if (isset($h[$left]) && isset($h[$right])) {
                  $j = ($this->compare($h[$left], $h[$right]) >= 0)
                      ? $left : $right;
                }
                else if (isset($h[$left])) {
                  $j = $left; // левый потомок
                }
                else {
                  $j = $right; // правый потомк
                }
 
                // меняем местами с корнем
                list($this->heap[$root], $this->heap[$j]) = 
                  array($this->heap[$j], $this->heap[$root]);
 
                // рекурсивно перебираем кучу относительно
                // нового корневого узла $j
                $this->adjust($j);
            }
        }
    }
}
</code>

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

<code class="php">public function insert($item) {
    // вставим новые элементы в конец кучи
    $this->heap[] = $item;
 
    // определим им корректное место
    $place = $this->count();
    $parent = floor($place / 2);
    // пока не на вершине и больше родителя
    while (
      $place > 0 && $this->compare(
        $this->heap[$place], $this->heap[$parent]) >= 0
    ) {
        // меняем местами
        list($this->heap[$place], $this->heap[$parent]) =
            array($this->heap[$parent], $this->heap[$place]);
        $place = $parent;
        $parent = floor($place / 2);
    }
}
</code>

Посмотрим что у нас получилось и попробуем вставить несколько значений в кучу:

<code class="php"><?php
$heap = new BinaryHeap();
$heap->insert(19);
$heap->insert(36);
$heap->insert(54);
$heap->insert(100);
$heap->insert(17);
$heap->insert(3);
$heap->insert(25);
$heap->insert(1);
$heap->insert(67);
$heap->insert(2);
$heap->insert(7);
</code>

Если мы попробуем вывести все это, то получим следующее:

<code class="php">Array
(
    [0] => 100
    [1] => 67
    [2] => 54
    [3] => 36
    [4] => 19
    [5] => 7
    [6] => 25
    [7] => 1
    [8] => 17
    [9] => 2
    [10] => 3
)
</code>

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

<code class="php"><?php
while (!$heap->isEmpty()) {
    echo $heap->extract() . "n";
}
</code>

<code class="html">100
67
54
36
25
19
17
7
3
2
1
</code>

SplMaxHeap и SplMinHeap
К счастью, для нас уже есть готовые реализации SplHeap, SplMaxHeap и SplMinHeap. Все что нам нужно сделать это только унаследовать их и переопределить метод сравнения, например так:

<code class="php"><?php
class MyHeap extends SplMaxHeap
{
    public function compare($item1, $item2) {
        return (int) $item1 - $item2;
    }
}
</code>

Данный метод выполнит любое сравнение двух узлов и в случае SplMaxHeap он возвращает положительное число если $item1 больше $item2, 0 если они равны друг другу и отрицательное, если $item2 больше $item1. Если мы наследуем SplMinHeap, то он вернет положительное число, если $item1 меньше $item2.

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

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

Как и в случае SplHeap, нужно лишь унаследовать SplPriorityQueue и переопределить метод сравнения:

<code class="php"><?php
class PriQueue extends SplPriorityQueue
{
    public function compare($p1, $p2) {
        if ($p1 === $p2) return 0;
        // в порядке возрастания приоритета, меньшее значение
        // означает больший приоритет
        return ($p1 < $p2) ? 1 : -1;
   }
}
</code>

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

Проверим работу приоритетной очереди, в качестве чисел зададим приоритет:

<code class="php"><?php
$pq = new PriQueue();
$pq->insert('A', 4);
$pq->insert('B', 3);
$pq->insert('C', 5);
$pq->insert('D', 8);
$pq->insert('E', 2);
$pq->insert('F', 7);
$pq->insert('G', 1);
$pq->insert('H', 6);
$pq->insert('I', 0);
  
while ($pq->valid()) {
    print_r($pq->current());
    echo "n";
    $pq->next();
}
</code>

Что в итоге выдаст нам следующее:

<code class="html">I
G
E
B
A
C
H
F
D 
</code>

В данном случае наши элементы идут в порядке убывания приоритета — от самого высокого к самому низкому (меньшее значение — больший приоритет). Можно поменять порядок выдачи элементов просто изменив метод сравнения, чтобы тот возвращал положительное число, если $p1 больше чем $p2.

По-умолчанию, извлекается только значение элемента. Если нужно получать только значения приоритета, или же значения и их приоритет, нужно установить соответствующий флаг извлечения:

<code class="php"><?php
// извлечь только приоритет
$pq->setExtractFlags(SplPriorityQueue::EXTR_PRIORITY);
 
// значение и приоритет (возвратит ассоциативный массив
// для каждого элемента)
$pq->setExtractFlags(SplPriorityQueue::EXTR_BOTH);
</code>

Графы
За графами стоит довольно много реальных применений — оптимизация сетей, маршрутизация или же анализ социальных сетей. Google PageRank, рекомендации от Amazon — вот некоторые примеры их использования. В этой части статьи я попробую объяснить две задачи, в которых они используются — проблемы поиска короткого пути и наименьшее число остановок.

Граф — математическая конструкция, используемая для представления отношений между парами ключ-значение. Граф состоит из набора вершин (узлов) и произвольного числа связей между узлами, соединяющих их между собой. Эти связи могут быть направленными (ориентированными) и ненаправленными. Направленная связь это связь между двумя узлами и связь A>B не является тем же самым, что и B>A. Ненаправленная же связь не имеет направления, таким образом связи A-B и B-A являются идентичными. Основываясь на этих правилах можно сказать, что деревья являются одним из ненаправленных графов, где каждая вершина соединена с одним из узлов простой связью.

Графы также могут иметь вес. Взвешенный граф, или сеть — граф, у которого для каждой связи указан вес («цена» перехода из узла A в узел B). Такие конструкции широко используются для определения наиболее оптимального пути, или же наиболее «дешевого» пути между двумя точками. Прокладка пути в GoogleMap осуществляется при помощи именно взвешенного графа.

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

Представим следующий граф:

image

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

  • 1. Создать очередь
  • 2. Добавляем туда корневой элемент и помечаем его как посещенный
  • 3. До тех пор пока очередь не пуста:
    • 3a. извлекаем текущий узел
    • 3b. если текущий узел является искомым — останавливаемся

    • 3c. иначе добавляеем в очередь каждый непосещенный соседний узел и помечаем его как посещенный

Но как мы узнаем какие узлы соседние или непосещенные не прибегая к обходу графа? Это подводит нас к вопросу о том, как графы могут быть смоделированы.

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

imageimage

В матрице, на пересечении узлов ставится «1», если узлы являются соседями.

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

<code class="php"><?php
$graph = array(
  'A' => array('B', 'F'),
  'B' => array('A', 'D', 'E'),
  'C' => array('F'),
  'D' => array('B', 'E'),
  'E' => array('B', 'D', 'F'),
  'F' => array('A', 'E', 'C'),
);
</code>

И напишем наш поиск в ширину:

<code class="php"><?php
class Graph
{
  protected $graph;
  protected $visited = array();
 
  public function __construct($graph) {
    $this->graph = $graph;
  }
 
  // найдем минимальное число прыжков (связей) между 2 узлами

  public function breadthFirstSearch($origin, $destination) {
    // пометим все узлы как непосещенные
    foreach ($this->graph as $vertex => $adj) {
      $this->visited[$vertex] = false;
    }
 
    // пустая очередь
    $q = new SplQueue();
 
    // добавим начальную вершину в очередь и пометим ее как посещенную
    $q->enqueue($origin);
    $this->visited[$origin] = true;
 
    // это требуется для записи обратного пути от каждого узла
    $path = array();
    $path[$origin] = new SplDoublyLinkedList();
    $path[$origin]->setIteratorMode(
      SplDoublyLinkedList::IT_MODE_FIFO|SplDoublyLinkedList::IT_MODE_KEEP
    );
 
    $path[$origin]->push($origin);
 
    $found = false;
    // пока очередь не пуста и путь не найден
    while (!$q->isEmpty() && $q->bottom() != $destination) {
      $t = $q->dequeue();
 
      if (!empty($this->graph[$t])) {
        // для каждого соседнего узла
        foreach ($this->graph[$t] as $vertex) {
          if (!$this->visited[$vertex]) {
            // если все еще не посещен, то добавим в очередь и отметим
            $q->enqueue($vertex);
            $this->visited[$vertex] = true;
            // добавим узел к текущему пути
            $path[$vertex] = clone $path[$t];
            $path[$vertex]->push($vertex);
          }
        }
      }
    }
 
    if (isset($path[$destination])) {
      echo "из $origin в $destination за ", 
        count($path[$destination]) - 1,
        " прыжков";
      $sep = '';
      foreach ($path[$destination] as $vertex) {
        echo $sep, $vertex;
        $sep = '->';
      }
      echo "n";
    }
    else {
      echo "Нет пути из $origin в $destinationn";
    }
  }
}
</code>

Запустив этот пример мы получим следующее:

Взглянуть на граф еще разimage

<code class="php"><?php
$g = new Graph($graph);
 
// минимальное число шагов из D в C
$g->breadthFirstSearch('D', 'C');
// вывод:
// из D в C за 3 шага
// D->E->F->C
 
// минимальное число шагов из B в F
$g->breadthFirstSearch('B', 'F');
// вывод:
// из B в F за 2 шага
// B->A->F
 
// минимальное число шагов из A в C
$g->breadthFirstSearch('A', 'C');
// вывод:
// из A в C за 2 шага
// A->F->C
 
// минимальное число шагов из A в G
$g->breadthFirstSearch('A', 'G');
// вывод:
// Пути из A в G нет
</code>

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

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

Один из знаменитых алгоритмов, направленных на решение данной проблемы был придуман в 1959 году 29-летним ученым по имени Эдсгер Вибе Дейкстра. Узнать подробнее про алгоритм можно в википедии или посмотреть на него в хабрапосте от splitface. В общих же чертах, решение Дейкстры сводится к проверке каждой связи между всеми возможными парами узлов, начиная от стартового узла, и поддерживая обновленным набор узлов с кратчайшей дистанцией, пока целевой узел не будет достигнут, если это возможно.

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

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

image

<code class="php"><?php
$graph = array(
  'A' => array('B' => 3, 'D' => 3, 'F' => 6),
  'B' => array('A' => 3, 'D' => 1, 'E' => 3),
  'C' => array('E' => 2, 'F' => 3),
  'D' => array('A' => 3, 'B' => 1, 'E' => 1, 'F' => 2),
  'E' => array('B' => 3, 'C' => 2, 'D' => 1, 'F' => 5),
  'F' => array('A' => 6, 'C' => 3, 'D' => 2, 'E' => 5),
);
</code>

Реализуем алгоритм с использованием приоритетной очереди для создания списка всех «неоптимизированных» узлов:

<code class="php"><?php
class Dijkstra
{
  protected $graph;
 
  public function __construct($graph) {
    $this->graph = $graph;
  }
 
  public function shortestPath($source, $target) {
    // массив кратчайших путей к каждому узлу
    $d = array();
    // массив "предшественников" для каждого узла
    $pi = array();
    // очередь всех неоптимизированных узлов
    $Q = new SplPriorityQueue();
 
    foreach ($this->graph as $v => $adj) {
      $d[$v] = INF; // устанавливаем изначальные расстояния как бесконечность
      $pi[$v] = null; // никаких узлов позади нет
      foreach ($adj as $w => $cost) {
        // воспользуемся ценой связи как приоритетом
        $Q->insert($w, $cost);
      }
    }
 
    // начальная дистанция на стартовом узле - 0
    $d[$source] = 0;
 
    while (!$Q->isEmpty()) {
      // извлечем минимальную цену
      $u = $Q->extract();
      if (!empty($this->graph[$u])) {
        // пройдемся по всем соседним узлам
        foreach ($this->graph[$u] as $v => $cost) {
          // установим новую длину пути для соседнего узла
          $alt = $d[$u] + $cost;
          // если он оказался короче
          if ($alt < $d[$v]) {
            $d[$v] = $alt; // update minimum length to vertex установим как минимальное расстояние до этого узла
            $pi[$v] = $u;  // добавим соседа как предшествующий этому узла
          }
        }
      }
    }
 
    // теперь мы можем найти минимальный путь
    // используя обратный проход
    $S = new SplStack(); // кратчайший путь как стек
    $u = $target;
    $dist = 0;
    // проход от целевого узла до стартового
    while (isset($pi[$u]) && $pi[$u]) {
      $S->push($u);
      $dist += $this->graph[$u][$pi[$u]]; // добавим дистанцию для предшествующих
      $u = $pi[$u];
    }
 
    // стек будет пустой, если нет пути назад
    if ($S->isEmpty()) {
      echo "Нет пути из $source в $targetn";
    }
    else {
      // добавим стартовый узел и покажем весь путь 
      // в обратном (LIFO) порядке
      $S->push($source);
      echo "$dist:";
      $sep = '';
      foreach ($S as $v) {
        echo $sep, $v;
        $sep = '->';
      }
      echo "n";
    }
  }
}
</code>

Можно заметить, что решение Дейкстры — простой вариант поиска в ширину. Вернемся к примеру и опробуем его:

<code class="php"><?php
$g = new Dijkstra($graph);
 
$g->shortestPath('D', 'C');  // 3:D->E->C
$g->shortestPath('C', 'A');  // 6:C->E->D->A
$g->shortestPath('B', 'F');  // 3:B->D->F
$g->shortestPath('F', 'A');  // 5:F->D->A 
$g->shortestPath('A', 'G');  // Нет пути из A в G
</code>

Все. На этом, судя по всему, статьи от Ignatius Teo по структурам закончились. Благодарю всех прочитавших, не ожидал, что первую часть так много человек поместит в избранное, хотя все мы знаем что избранное редко когда читается и все посты остаются там навсегда :)

Бенчмарки производительности реализаций данных структур скопипастил отсюда
взглянутьimageimage


imageimage


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

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

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Вебкаст Dell: обновление линейки Alienware

Привет, уважаемые хабровчане!

С вашего позволения, мы сразу перейдем к делу :)

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

Мы раньше как-то не задумывались о том, что такие «междусобойчики» могут быть полезны кому-то, кроме нас и наших партнеров, но вдруг (внезапно!) вспомнили о Хабре и его обитателях — ведь им (то есть вам) тоже может быть интересно узнать, скажем, о новом продукте Dell не из сухого пресс-релиза или детального обзора на одном из профильных сайтов, а из первых рук.

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

image
Как на него попасть?
  1. Кликните сюда.
  2. Введите некоторые личные данные, которые мы обещаем не использовать против вас (в том числе и для спама).
  3. В ваш ящик упадет письмо со ссылкой.
  4. В пятницу, 30 августа, в 14:00 по Москве перейдите по этой ссылке и включайтесь.
  5. Всё.
Если вы захотите принять участие в последующих наших вебкастах, еще раз регистрироваться не надо будет, просто перейти по специальной ссылке и ввести пароль, указанный в самом первом письме. Расписанием и специальными ссылками будем оперативно с вами делиться.

Напоследок вопрос, даже два: насколько вам интересно узнавать о новых вебинарах в нашем блоге? Вебинары на какую тему вам было бы интересно посетить?

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


GetThemAll или бери от интернета лучшее!

Сегодня я хотел бы рассказать о нашем приложении GetThemAll для Windows Phone. Да, я знаю, что приложени не новое, но в рунете о нем известно немного, тогда как на западе оно пользуется невероятной немалой популярностью.

image



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

image

Скаченное видео можно просматривать в встроенном удобном плеере. Также присуствует удобный файл-менеджер.

image

Скаченный файлы можно отправить на SkyDrive или сразу на компьютер, используюя GetThemAll Receiver.

Скачать GetThemAll для Windows Phone
Также есть GetThemAll для Android и для десктопного браузера Chrome

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


[RSS-пост] Правообладатели и интернет — от спора к рынку. Позиция Яндекса

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

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

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

Действительно, почему для просмотра фильма необходимо пойти в кинотеатр в указанное им время, заплатить не только за само кино, но и за содержание здания, нюхать попкорн, да ещё смотреть рекламу перед началом? Конечно, есть любители коллективного просмотра, своего рода «выхода в свет», они понимают, за что платят. Но для многих желающих посмотреть фильм кинотеатр — навязанная услуга. На диске фильм появляется тогда и в таком качестве, в каком будет угодно правообладателям. Диск надо где-то купить. Если фильм старый, иногда его вовсе нельзя найти, а иногда — только в крупных интернет-магазинах, то есть приходится ждать доставки и платить за неё. Вопрос — почему я не могу удобным образом посмотреть фильм, скачав его в интернете легально в понимании правообладателей, то есть заплатив им деньги? Кстати, при характерной цене DVD в 99 рублей, куда включены расходы на печать и дистрибуцию, рискну предположить, что правообладателю достается не больше 20-30 рублей с экземпляра. Так вот, вопрос — почему отсутствует хорошее платное предложение? Хорошее — это с достаточно полным каталогом фильмов, музыки и других объектов в хорошем качестве.

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

Общая запутанность прав — общемировая ситуация копирайта. Хорошо известно, что многие произведения вообще не могут быть опубликованы, потому что нет способа урегулировать правовые вопросы. Кроме того, правообладатель вообще не обязан давать доступ к своему объекту прав даже после того, как тот был хотя бы единожды опубликован. Например, как можно легально посмотреть в русской озвучке прекрасный итальянский мини-сериал 60-х годов «Дон Камилло» с Фернанделем? А что делать, когда коммерсанты решат торговать только раскрашенным Штирлицем? И уж тем более правообладатель не обязан выпускать что-либо в хорошем качестве. Скажем, на DVD часто попадаются фильмы с плохими цветами и звуком.

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

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

Дискуссия правообладателей и их противников идёт не в противопоставлении «платно»/«халява», как это часто пытаются представить, а в противоречии собаки на сене и голодного быка.

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

Елена Колмановская, сооснователь Яндекса.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Собеседование на должность PHP Backend Developer в Германии

Коротко обо мне: программирую c 2003 года. По образованию IT specialist и Application Developer. В последние годы основным направлением деятельности была интернет-магазинов аля Hugo Boss и Tommy Hilfiger. Проснувшись утром в один прекрасный день, пришло осознание, что пора в этой жизни что-то менять.

Хочу поделиться своим опытом прохождения собеседований на должность Backend Developer в Германии. Собеседований, в свое время, пришлось пройти немало. Но о двух наиболее запоминающихся хочется рассказать, возможно, кому-то и пригодится в будущем мой опыт.

Компания 1.

Основное направление деятельности — разработка сайтов.
Кол-во сотрудников: более 30.

Описание должности:
1. Хорошие знания PHP и многолетний опыт работы
2. Прагматичное мышление, ориентация на результат
3. SOLID, DRY, YAGNI vs. BUFD
4. Понимание смысла TDD и BDD и умение их применять
5. Понимание технологий HTTP, Frameworks, Patterns
6. Умение объяснять принятые технологические решения
7. Высокий уровень мотивации и желание работать именно в данной компании



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

Через 3 дня пришел ответ с приглашением прийти на собеседование в офис. Назначили дату, предупредили, что вся процедура займет примерно полдня. Сначала фраза «полдня» меня смутила, потом, оказавшись непосредственно на месте все встало на свои места. Об этом подробнее:

Началось все с небольшого интервью ( 30 мин.)

Вопросы, которые задавали:

Откуда вы узнали о нашей компании?
Какие у вас ожидания от предстоящей работы?
Есть ли у вас опыт работы в компаниях с плоской иерархией?
Почему вы не хотите открыть свою IT-фирму? (в моем резюме были указаны 3 года фриланса)
С какими языками программирования вы работали и почему именно остановились на PHP?
Что знаете об Agile?
Что такое SOLID и каковы основные принципы?
Если бы вы придумали свой собственный язык программирования, какие фичи вы бы переняли из других языков?

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

Затем небольшая кофейная пауза и экскурсия по офису. (20 мин.)
Далее посадили в пару к одному из программистов и дали задание, которое мы с ним вместе должны были сделать. (1,5 часа)
Обеденный перерыв со всей командой разработчиков (1 час)
Затем попросили дать отзыв, как, на мой взгляд, прошло собеседование, как мне понравилась фирма и не пропало ли желание в ней работать. (10 мин.) Попрощались, обещали связаться со мной в течение 2ух недель.

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

image

Компания 2.

Основное направление деятельности — разработка онлайн-игр.
Кол-во сотрудников: более 300.

Описание должности:
1. PHP 5.4
2. Желателен опыт работы в game development
3. MySQL
4. Знание фрэймвокров аля ZF2
5. Опыт в тестировании
6. Знание REST и RPC
7. Осознание, что Linux это не животное
8. Особая любовь с HTML/CSS и JavaScript (jQuery)
9. Понимание разницы между ‘agile’ и ‘хаос’
10. Свободное владение английским и немецким языками

Собеседование
На этот раз нашли меня, нашли через немецкую сеть xing.com. Вкратце описали должность и требования и в случае заинтересованности попросили отправить резюме.
Game Development – штука интересная, поэтому не долго думая резюме было отослано. Единственное, где оставались сомнения — это знания английского. Читаю и понимаю все, но не говорю.
На следующий день звонок с приглашением на личную встречу.

На самом собеседовании присутствовали 3 человека: HR-работник, который меня нашел в Xing, руководитель отдела разработки и рядовой PHP-Developer.

Интервью. (30 мин.)

Вопросы, которые задавали:

Есть ли у вас опыт работы в Game Development?
Почему больше нравится Backend, а не Frontend?
Почему вы хотите уйти из фирмы, где проработали 9 лет?
Как вы относитесь к внеурочной работе?
Чем вы занимаетесь в свободное время?
В какой области вы считаете себя наиболее успешным, а в какой области есть потенциал роста?
Кем вы видите себя через 10 лет?

В конце интервью руководитель отдела разработки сказал, что он заинтересован в совместной работе. Сказал, что в ближайшее время мне пришлют тестовое задание, с которым надо будет справится в течение максимум 2 часов.
А вот и само задание:

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

· Акцент на функциональность, а не на дизайн

· Таблицы в БД должны быть понятны и просто оформлены

· Комментарий должен содержать Имя, Email и Текст

· Внешний вид комментария на усмотрение

· В случае добавления в комментарий, она должна быть рабочая и кликабельная автоматически

· Для избежания спама имплементировать Капчу

· Новые комментарии должны автоматически публиковаться на странице сайта (а не после обновления страницы)

· Удобное и понятное описание CSS и JavaScript

· Во всех браузерах форма должна выглядеть одинаково

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

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

Мои выводы
1. Если вы пишете резюме, то вписывайте туда все программы и фрэймворки, с которыми вы хоть 30 мин. в жизни, но работали.
2. В мотивационном письме постарайтесь себя вкусно продать, при этом проштудируйте историю фирмы и узнайте все о корпоративной культуре. Во многих фирмах в Германии тебя могут не принять на работу из-за того, что ты не понравился команде. И никакой многолетний опыт работы и потрясающая квалификация тебя не спасут.
3. Знания английского, как показывает практика, не всегда нужны в том объеме, о котором пишут в описании должности. Чаще всего речь идет об обычном понимании языка и умении читать технические вещи на английских сайтах, блогах и т.п. Т.е. не обязательно быть птицей-говоруном.
4. Знайте себе цену, заранее посмотрите годовой уровень зарплат в вашей области и просите на 20% больше, чем вы хотели бы получать в итоге. В большинстве случаев будет торг.
5. При личном собеседовании важна инициативность и коммуникабельность. Постарайтесь с ходу предложить пару идей для развития фирмы и идеи эти обосновать.
6. Задавайте встречные вопросы и показывайте заинтересованность.
7. Если вам предложат выполнить какое-нибудь задание, не пугайтесь и свободно пользуйтесь интернет-ресурсами, т.к. главное – показать результат, а не заученные в университете истины.
8. Каждую строку кода будьте готовы объяснить.
9. Не бойтесь давать фидбэк о собеседовании. Просто сказать, что вам все понравилось, недостаточно. Если понравилось, уточните, что именно, если есть вопросы, задавайте сразу. Если вопросы появились уже после собеседования, отправьте их по Email.
10. Принципы SOLID спрашивают почти везде.
11. В резюме указывайте ник в Github.
12. Continuous integration тоже часто спрашивают.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


В Windows Phone Store за $19



Ещё только вчера, я приглашал скорее зарегистрироваться за $19 тем, кто хочет начать публиковать свои приложения в Windows Phone Store, но цена регистрации в $99 ему кажется слишком большой.

И сегодня Todd Brix порадовал нас хорошей новостью


И если перейти по ссылке dev.windowsphone.com/en-us/join, можно увидеть, что годовая подписка теперь стоит $19 бессрочно:



Традиционно в завершение напоминаю, что для студентов, участников программы DreamSpark, и стартапов, участников программы BizSpark — регистрация в Windows Phone Store — бесплатна.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


Moto X официально поступил в продажу



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

Все бы хорошо, но на данный момент для заказа доступна только версия с контрактом от AT&T, цена на которую начинается от $199.99.

При заказе можно выбрать и опцию «No Contract», что повышает стоимость телефона до $579.99 за 16-ти гигабайтную версию. Примерно столько, как ожидалось, должна стоить разлоченная версия смартфона. Однако при выборе данной опции мы получаем свободный от контрактных обязательств, но все же привязанный к оператору телефон.

О своих планах о начале продаж полноценно разлоченного телефона, Motorola по прежнему хранит молчание.

А тем временем Google снизил цену Nexus 4 на целых $100, и теперь стоимость 8-гигабайтной модели составляет всего $199, а 16-гигабайтная — соответственно $249. Эти цены, разумеется, актуальны только при заказе устройства непосредственно на Google Play.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


[Из песочницы] Установка и использование Archipel для управления виртуальными машинами


Хочу поделиться удобным способом создания и управления виртуальными машинами в графическом режиме для OS Linux.
Archipel – это маштабируемое решение для управления виртуальными машинами и гипервизорами с помощью графического интерфейса. Archipel позволяет удобно управлять как несколькими виртуальными машинами на одном сервере, так и сотнями виртуалок, размещенных на десятках серверов в разных датацетрах.
Archipel использует протокол XMPP в качестве системы обмена между своими подсистемами. Более подробную информацию можно получить на сайте проекта archipelproject.org/

Archipel – очень простое приложение, для установки достаточно выполнить
<code class="bash">$ easy_install archipel-agent && archipel-initinstall
</code>
Но для того, что бы все заработало, нужно провести некоторые предварительные настройки.
Для работы archipel требует установленный и работающий XMPP сервер (ejabberd) и любой веб-сервер для хостинга Archipel Agent (UI).

Мы установим Archipel в односерверном варианте на Ubuntu 12.04 LTS, в нашем случае ejabberd, nginx и виртуальные машины будут расположены на одном сервере. В более серьезных проектах все это можно разнести по разным серверам.

Установка и настройка XMPP
Нам необходимо установить ejabberd версии не ниже 2.1.6 с включенными модулями mod_admin_extra и ejabberd_xmlrpc (не обязательно).
Устанавливаем ejabberd из репозитория:
<code class="bash">$ aptitude install ejabberd
</code>
Модуль mod_admin_extra уже входит в поставку, так что отдельно его устанавливать не нужно.

Настраиваем ejabberd для работы archipel.
По умолчанию в /Ubuntu настройки ejabberd заточены под простой «чат-сервер», и они не совсем подходят для наших задач, где требуется полноценный XMPP сервер.
Для работы требуется иметь корректный FQDN (полное имя домена). Для избежание дальнейших граблей, очень желательно установить его до настройки ejabberd и привести в соответствие hostname.
Для примера мы будем использовать FQDN archipel.example.com. При установке обязательно нужно заменить этот адрес на адрес вашего сервера.
<code class="bash">echo archipel.example.com > /etc/hostname
hostname -b -F /etc/hostname
</code>
Так же не забудьте изменить /etc/hosts в соответствии с вашим адресом.
Убедитесь, что сервер доступен по указанному адресу с сервера и вашего компьютера.
<code class="bash">ping archipel.example.com
</code>
Сохраним копию конфигурационного файла ejabberd
<code class="bash">mv /etc/ejabberd/ejabberd.cfg /etc/ejabberd/ejabberd.cfg.orig
</code>
Сам файл ejabberd.cfg приводим к следующему виду:
Скрытый текст
<code>%%%
%%%               ejabberd configuration file
%%%  
%%%              Archipel Sample Configuration

%%%   =======================
%%%   OVERRIDE STORED OPTIONS
  
%% loglevel: Verbosity of log files generated by ejabberd.
{loglevel, 3}.


%%%   ================
%%%   SERVED HOSTNAMES

%% CHANGE FQDN to your FQDN
{hosts, ["FQDN"]}.
 

%%%   ===============
%%%   LISTENING PORTS

{listen,
 [
  %% If you have compiled the ejabberd-xmlrpc, uncomment the following line
  %% {4560, ejabberd_xmlrpc, []},

  {5222, ejabberd_c2s, [
            {access, c2s},
            starttls, 
            {certfile, "/etc/ejabberd/ejabberd.pem"},
            {max_stanza_size, 65536000}
               ]},
  {5269, ejabberd_s2s_in, [
            {max_stanza_size, 65536000}
               ]},
  {5280, ejabberd_http, [
             http_bind,
             http_poll,
             web_admin
               ]},
  %% Make a SSL version of the BOSH service
  {5281, ejabberd_http, [
             http_bind,
             http_poll,
             tls,{certfile, "/etc/ejabberd/ejabberd.pem"}
               ]}
 ]}.


%%%   ===============
%%%   S2S

{route_subdomains, s2s}.
{s2s_use_starttls, true}.
{s2s_default_policy, allow}.    
{s2s_certfile, "/etc/ejabberd/ejabberd.pem"}.


%%%   ==============
%%%   AUTHENTICATION

{auth_method, internal}.


%%%   ===============
%%%   TRAFFIC SHAPERS

{shaper, normal, {maxrate, 1000}}.
{shaper, fast, {maxrate, 50000}}.


%%%   ====================
%%%   ACCESS CONTROL LISTS

%% CHANGE FQDN to your FQDN
{acl, admin, {user, "admin", "FQDN"}}.
{acl, local, {user_regexp, ""}}.


%% if you HAVE NOT compiled ejabberd-xmlrpc module, you
%% Need to declare all your hypervisors as ejabberd admin
%% The hypervisor JID is defined in archipel.conf. By default it
%% it is hypervisor@FQDN 

{acl, admin, {user, "hypervisor", "FQDN"}}.
%% {acl, admin, {user, "hypervisor-x", "FQDN"}}.
%% {acl, admin, {user, "hypervisor-n", "FQDN"}}.


%%%   ============
%%%   ACCESS RULES

{access, max_user_sessions, [{10, all}]}.
{access, local, [{allow, local}]}.
{access, c2s, [{deny, blocked}, {allow, all}]}.
{access, c2s_shaper, [{none, admin}, {none, all}]}.
{access, s2s_shaper, [{fast, all}]}.
{access, announce, [{allow, admin}]}.
{access, configure, [{allow, admin}]}.
{access, muc_admin, [{allow, admin}]}.
{access, muc, [{allow, all}]}.
{access, muc_create, [{allow, local}]}.
{access, pubsub_createnode, [{allow, all}]}.


%%%   ================
%%%   DEFAULT LANGUAGE

{language, "en"}.
      

%%%   =======
%%%   REGISTRATION

{access, register, [{allow, all}]}.
{registration_timeout, infinity}.

%%%   =======
%%%   MODULES

{modules,
 [
  {mod_adhoc,    []},
  {mod_announce, [{access, announce}]}, % requires mod_adhoc
  {mod_caps,     []}, 
  {mod_configure,[]},
  {mod_disco,    []},
  {mod_http_bind,[
               {max_inactivity, 480}   % timeout value for the BOSH, usefull for a large number of VM
             ]},
  {mod_irc,      []},
  {mod_last,     []},
  {mod_muc,      [
          {access, muc},
          {access_create, muc_create},
          {access_persistent, muc_create},
          {access_admin, muc_admin}
         ]},
  {mod_offline,  []},
  {mod_privacy,  []},
  {mod_private,  []},
  {mod_pubsub,   [ % requires mod_caps
          {access_createnode, pubsub_createnode},
          {ignore_pep_from_offline, true},
          {last_item_cache, false},
          {plugins, ["flat", "hometree", "pep"]},
          {max_items_node, 1000}
         ]},
  {mod_register, [
          {access, register}
         ]},
  {mod_roster,   []},
  {mod_shared_roster,[]},
  {mod_time,     []},
  {mod_vcard,    []},
  {mod_version,  []},
  {mod_admin_extra, []}
 ]}.
</code>


В файле ejabberd.cfg меняем все вхождения FQDN на ваш адрес сервера
<code class="bash">sed –I 's/FQDN/archipel.example.com/' /etc/ejabberd/ejabberd.cfg
</code>
Создадим новый самоподписанный сертификат для ejabberd. Обязательно укажите ваш FQDN в запросе Common Name.
<code class="bash">openssl req -new -x509 -newkey rsa:1024 -days 3650 -keyout /etc/ejabberd/privkey.pem -out /etc/ejabberd/ejabberd.pem
openssl rsa -in /etc/ejabberd/privkey.pem -out /etc/ejabberd/privkey.pem
cat /etc/ejabberd/privkey.pem >> /etc/ejabberd/ejabberd.pem
rm /etc/ejabberd/privkey.pem
</code>
После этого запускаем ejabberd
<code class="bash">service ejabberd start
</code>

Если ejabberd не запускается – проверьте наличие процесса beam в списке запущенных процессов. При необходимости убейте этот процесс.
Так же бывает ошибка при изменении hostname после первого запуска ejabberd. В этом случае нужно очистить директорию /var/lib/ejabberd/ и перезапустить сервис ejabbed.


Проверить работоспособность можно с помощью ejabberdctl:
<code class="bash">$ ejabberdctl status
The node ejabberd@archipel is started with status: started
ejabberd 2.1.10 is running in that node
</code>
Создаем аккаунт администратора (имя желательно использовать admin):
<code class="bash">$ ejabberdctl register admin archipel.example.com yourpassword
</code>
Мы закончили с настройкой ejabberd и теперь можно приступить к установке Archipel agent

Archipel Agent.
Работа Archipel agent бессмысленна без средств виртуализации и гипервизора, которыми он будет управлять.
Для работы нам требуется:
  • Современный дистрибутив с поддержкой KVM
  • qemu
  • libvirt (0.8.7+)
  • python 2.7+
  • qemu-img
  • python-imaging
  • numpy

Установим зависимости:
<code class="bash">aptitude install python-libvirt libvirt-bin libvirt0 python-imaging python-numpy qemu-utils python-pip qemu-kvm python-sqlalchemy-ext
</code>
И сам агент:
<code class="bash">easy_install archipel-agent
archipel-initinstall
</code>
Создаем pubsub nodes:
<code class="bash">archipel-tagnode --jid=admin@archipel.example.com --password=YOURPASSWORD --create
archipel-rolesnode --jid=admin@archipel.example.com --password=YOURPASSWORD --create
archipel-adminaccounts --jid=admin@archipel.example.com --password=YOURPASSWORD --create
</code>
Здесь admin и YOURPASSWORD нужно заменить на ваши данные, которые вводились при создании аккаунта администратора.
Теперь нужно проверить файл /etc/archipel/archipel.conf, особенно обратить внимание на строчку xmpp_server, она должна совпадать с вашим FQDN.
Пробуем запустить агента:
<code class="bash">/etc/init.d/archipel start
</code>
Если запуск не удался, можно запустить агента вручную с помощью команды
runarchipel, так будут видны ошибки. 
Логи агента хранятся в файле /var/log/archipel/archipel.log

Если запуск прошел успешно, в список подключенных пользователей jabber добавиться наш агент:
<code class="bash">$ ejabberdctl connected_users
archipel.example.com@archipel.example.com/archipel.example.com
</code>
Для проверки корректности работы можно выполнить расширенный тест:
<code class="bash">archipel-testxmppserver --jid=admin@FQDN --password=YOURPASSWORD
</code>
Если у вас не установлен модуль xmlrpc – 8 тест и далее выполняться с ошибками. На дальнейшую работу это не повлияет.

Установка клиента.
Клиент Archipel написан полностью на Javascript. Для работы он не требует никаких серверных языков типа php, python, java или баз данных. Достаточно просто распаковать архив и поместить его в папку веб-сервера.
Так же можно использовать публичную версию клиента, доступную по адресу app.archipelproject.org/.

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

<code class="bash"># aptitude install nginx
cd /usr/share/nginx/www/
wget http://nightlies.archipelproject.org/latest-archipel-client.tar.gz
tar zxf latest-archipel-client.tar.gz
</code>

Теперь можно открыть клиента Archipel в браузере:
http://archipel.example.com/Archipel/

Должна отобразиться такая страница:

В качестве Jabber ID вводим admin@archipel.example.com и установленный пароль администратора.
Не забудьте везде заменить archipel.example.com на адрес вашего сервера!!!
После входа можно приступать к созданию виртуальных машин.

Установка Windows Server 2008R2 как гостевую ОС
Для примера попробуем создать виртуальную машину с Windows Server 2008 R2.
В первую очередь нам нужно добавить аккаунт гипервизора в наш контактный лист.

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

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

После этого можно выделить новую виртуальную машину в списке контактов и перейти к ее настройке.
В настройках можно указать размер RAM (Definition > Basics > Memory), количество процессоров (Definition > Basics > Virtual CPUs), порядок загрузки (Definition > Basics > Boot from); добавить виртуальные диски cd/dvd (Definition > Virtual Medias), виртуальные сети (Definition > Virtual Nics), диски (Disks) и другие. Так же можно делать снапшоты и подключаться через виртуальную консоль к компьютеру.
Настройки виртуальных сетей находятся в агенте, меню Networks.
После изменения настроек для их сохранения нужно нажать на кнопку Validate.

Для запуска тестового сервера мы добавим новую сеть с типом Nat, в этом случае виртуальная машина будет выходить в интернет с IP-адресом хоста. Если вы хотите выделить для виртуальной машины отдельный IP – можно использовать режим Bridge.

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

Все диски и образы храняться в папке /vm/ на компьютере-гипервизоре.
Предварительно добавляем в папку /vm/iso/ iso-образы windows server и драйверов virtio (можно взять на alt.fedoraproject.org/pub/alt/virtio-win/latest/images/bin/)
В Definition > Virtual Medias подключаем следующие диски:
  1. Drive type: disk, source type: file, source: «ваш созданный диск», bus: virtio, target: vda
  2. Drive type: cdrom, source type: file, source: iso с дистрибутивом, bus: , target: hdc
  3. Drive type: cdrom, source type: file, source: iso с virtio, bus: usb, target: hde
USB мы используем для второго cdrom из-за того, что поддерживается только 1 IDE канал.
В Virtual Nics создаем сетевую карту:
Type: Network, Source: имя созданной сети с nat, Model: virtio

После этого можно запустить виртуальную машину (Controls > Start) и подключиться к VNC Console


Windows 2008 R2 ничего не знает о virtio, поэтому мы подключили второй cdrom с драйверами и теперь можем их загрузить.
В списке драйверов выбираем Red Hat VirtIO SCSI Controller, после их загрузки появится системный диск, на который можно устанавливать Windows.

Дальнейшая установка проходит как обычно. После установки не забудьте добавить еще 2 драйвера с диска virtio: Network и Baloon (нужен для изменения памяти)

Осталось дать доступ к сервисам виртуальной машины с помощью маппинга портов либо установки и настройки vpn, но это уже тема других статей.

Источник: habrahabr.ru,
получено с помощью rss-farm.ru


[Перевод] LINQ против LSP

В качестве реакции на мой предыдущий пост о защитном программировании, один из моих читателей прислал мне такой вопрос:
[Один] очень известный сценарий защитного программирования встречается, когда входным параметром является
IEnumerable<T>

<code class="cs">public class Publisher { public Publisher(IEnumerable<Subscriber> subscribers) { // defensive copy -> good or bad? this.subscribers = subscribers.ToArray(); } // … } </code>
«Вы можете утверждать следующее: когда получатель намеревается использовать IEnumerable<T>
, он не должен предполагать, что последовательность неизменяема. Вы можете обозначить это, используя
ICollection, к примеру (прим.переводчика.: Я не уверен, что правильно перевёл последнее предложение. Возможно, не понял контекст, либо читатель блога Марка ошибся в своём вопросе. Разве может ICollection 
обозначать неизменяемую коллекцию, если этот интерфейс привносит методы, изменяющие коллекцию? По поводу перевода — в личку. Спасибо за понимание). В примере, приведённом выше, вызывающая сторона может молча добавить нового подписчика в свой список и автоматически производить инъекцию этого списка в ‘publisher’ (возможно, что именно это и задумал клиент класса). Однако, защитная копия сломает смысл, который ожидает клиент, потому что внедрённый список с этих пор будет находиться вне контроля вызывающей стороны. Это показывает то, как легко деталь реализации может изменить поведение, которое ожидает клиент.
«Причиной того, что вы часто видите подобный код, является наша любовь к неизменяемым объектам и во-вторых, из-за незнаний относительно того, какое влияние может оказать на производительность
IEnumerable. Однажды сделав копию, вы можете предсказывать производительность вашего класса, в противном случае – нет.
«Я склоняюсь к тому, чтобы сказать, что делать защитную копию – это плохо (после прочтения множества ваших записей в блоге), однако буду очень рад услышать ваше мнение по этому поводу.
Вопрос требует глубокого ответа.

Инкапсуляция.
IEnumerable<T> является одни из самых недопонимаемых интерфейсов в .NET. Этот интерфейс даёт очень немного гарантий и вызовы большей части методов на нём, могут, вообще говоря, нарушать принцип подстановки Барбары Лисков (LSP – Liskov Substitution Principle).
ToArray() является одним из них, потому что он предполагает, что последовательность, производимая итератором конечна, хотя она может и не являться таковой. Таким образом, если вы вызываете ToArray() на бесконечном итераторе, то вы в конечном итоге получите исключение.
Не имеет особого значения то, в каком месте вы вызовете ToArray()
– в конструкторе, или в методе класса, где собираетесь использовать
IEnumerable<T>. Однако, с точки зрения «отвалиться как можно раньше» и в целях защиты инвариантов класса, если класс требует, чтобы последовательность была конечной, вы можете утверждать, что нужно вызвать ToArray() 
(или
ToList()) в конструкторе. Однако, это ломает 4-й закон IoC Николы Маловича: конструкторы не должны производить никакой работы. Это должно заставить вам остановиться и задуматься: если вам нужен массив, вы должны объявить это требование сразу:

<code class="cs">public class Publisher { public Publisher(Subscriber[] subscribers) { this.subscribers = subscribers; } // … } </code>Заметьте, что вместо требования IEnumerable<T>
, эта версия требует массив и просто присваивает ссылку на него закрытому полю.
Однако, проблема в том, что массив это не совсем итератор. Самая значительная разница состоит в том, что в случае массива, класс Publisher может изменять элементы. Это может стать проблемой, если массив используется и другим клиентским кодом.
Другой проблемой является то, что если класс Publisher не нуждается в обладании возможностью изменять массив, это теперь нарушает принцип устойчивости, потому что конечный итератор был бы достаточно хорош для нужд класса, однако, не следует забывать, что он по-прежнему предъявляет необоснованное требование к своим клиентам.
Запрос передачи
ICollection<T>, как предлагают мои читатели, является ещё большим нарушением принципа устойчивости, потому что этот интерфейс добавляет 7 новых методой поверх IEnumerable<T>
— три из которых, предназначены исключительно для изменения коллекции.

LINQ и LSP
В своём предыдущем посте я говорил о конфликте между IQueryable и LSP, но даже ограничивая дискуссию рамками LINQ to Objects, выясняется, что LINQ содержит множество встроенных нарушений LSP.
Вспомним смысл LSP: вы должны иметь возможность передать любую реализацию интерфейса клиенту без изменения корректности системы. В то время как «корректность» является специфичной для приложения, наименьшим общим кратным должно являться то, что если метод работает корректно для одной реализации интерфейса, то он не должен выбрасывать исключения для другой. Впрочем, рассмотрим две реализации
IEnumerable<string>:
<code class="cs">new[] { "foo", "bar", "baz" }; </code>и вот такую:
<code class="cs">public class InfiniteStrings : IEnumerable<string> { public IEnumerator<string> GetEnumerator() { while (true) yield return "foo"; } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.GetEnumerator(); } } </code>
Как я уже говорил, вызов ToArray()
(или
ToList()) на этих двух реализациях меняет корректность системы, ибо вторая реализация (бесконечный итератор) станет причиной выброса исключения. Фактически, насколько я знаю, LSP-совместимыми LINQ-методами являются следующие:

  • Any()
  • AsEnumerable()
  • Concat(IEnumerable<T>)
  • DefaultIfEmpty()
  • DefaultIfEmpty(T)
  • Distinct (возможно...)
  • Distinct(IEqualityComparer<T>) (возможно...)
  • ElementAt(int)
  • ElementAtOrDefault(int)
  • First()
  • FirstOrDefault()
  • OfType<TResult>()
  • Select(Func<TSource, TResult>)
  • Select(Func<TSource, int, TResult>)
  • SelectMany(Func<TSource, IEnumerable<TResult>>)
  • SelectMany(Func<TSource, int, IEnumerable<TResult>>)
  • SelectMany(Func<TSource, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>)
  • SelectMany(Func<TSource, int, IEnumerable<TCollection>>, Func<TSource, TCollection, TResult>)
  • Single()
  • SingleOrDefault()
  • Skip(int)
  • Take(int)
  • Where(Func<TSource, bool>)
  • Where(Func<TSource, int, bool>)
  • Zip(IEnumerable<TSecond>, Func<TFirst, TSecond, TResult>)

  • Если вы можете обойтись использованием этих LINQ-методов, то вы можете быть спокойны. Если нет, вы возвращаетесь к выбору между IEnumerable или массивом, т.е., между нарушением LSP и принципа устойчивости.
    Это показывает необходимость наличия интерфейса конечного итератора, и, надо признать, что до написания этой статьи, я был не в курсе насчёт существования IReadOnlyCollection, но вот оно что: похоже, что это новый интерфейс, который появился только в .NET 4.5. Я думаю, что теперь начну пользоваться этим интерфейсом.

    Заключение.
    Подводя черту, надо сказать, что защитной копии IEnumerable следует избегать. Если вам удаётся обойтись использованием LSP-совместимых LINQ-методов, то всё хорошо (но рассмотрите возможность написания пары юнит-тестов с использованием бесконечных итераторов). Если вашим требованием является конечная последовательность и вы пишите под .NET 4.5, требуйте передачи
    IReadOnlyCollection<T>
    в качестве аргумента, вместо IEnumerable. Если вы требуете конечную последовательность и вы пишите под версией, выпущенной ранее версии .NET 4.5, требуйте передачи в качестве аргумента массива (и рассмотрите возможность написания пары юнит-тестов, которые проверят то, что ваши методы не изменяют массив).

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Перевод] Самые смешные комментарии в исходном коде

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

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

    <code>// 
    // Дорогой мейнтейнер:
    // 
    // Когда ты закончишь «оптимизировать» эту подпрограмму
    // и поймешь, насколько большой ошибкой было делать это,
    // пожалуйста, увеличь счетчик внизу как предупреждение
    // для следующего парня:
    // 
    // total_hours_wasted_here = 42
    //</code>

    <code>// Когда я начинал это писать, только Бог и я понимали, что я делаю
    // Сейчас остался только Бог</code>
    (Изначально цитату приписывают Карлу Вейерштрассу, относительно его математической статьи).

    <code>// иногда мне кажется, что компилятор игнорирует все мои комментарии</code>
    <code>// Я посвящаю весь свой код, всю работу своей жене Дарлин, которой
    // придётся содержать меня, наших троих детей и собаку, когда
    // это пойдет в паблик.</code>
    <code>// пьян, исправить позже</code>
    <code>// Магия. Не трогать.</code>
    <code>#define TRUE FALSE
    // Удачного дебаггинга, молокососы</code>
    <code>long john; // silver</code>
    (Так банально, что даже смешно).
    Долговязый Джон Сильвер (Long John Silver) — персонаж романа Роберта Льюиса Стивенсона «Остров сокровищ» — прим. пер.

    <code>long long ago; /* в далёкой-далёкой Галактике */</code>
    (Это даже компилируется в C99/C++0x).

    <code>/**
     * Всегда возвращает true.
     */
    public boolean isAvailable() {
        return false;
    }</code>
    (Это доказывает, почему код *всегда* лучше, чем комментарии)

    <code><!-- Here be dragons  --></code>

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Виртурилки прилетели!

    Итак, первый серьёзный (по нашим меркам) тираж железок успешно прошёл приёмку нами на заводе и официальную растаможку в России. Процент брака основных плат зашкалил за нуль и составил 0.5%. Очень неплохо, мы рассчитывали в худшем на 5-6 процентов брака. К слову, есть мысль отдать одну бракованую железку BarsMonster на вскрытие проца (если он заинтересуется, само собой).

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

    В общем, железки уже у нас на руках, теперь начинается самое интресное





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

    Дальше всё пошло практически по-плану. Завод высказал свои сроки (очередь, время на производство). К указанному сроку наш главный аппаратчик Саша совершил вояж в Гонконг, а потом и на завод в Китай, где лично принял всё железо после конечного тестирования. После приёмки последовала доставка всего железа в Россию на таможню, а затем и к нам «на склад».



    Сейчас мы уже готовимся рассылать заказанные железки (курьером, самовыносом, почтой, etc).

    Бонусные платы

    Мы обещали бесплатные бонусные платы, когда собирали предзаказы. Лидером по «хотелкам» стала силовая плата (моторшылд, в терминологии Ардуины), на втором месте — плата композитного видеовхода.

    Бонусные платы мы ещё не делали, так как все силы были брошены на основной комплект (без Виртурилки бонусные платы нафиг никому не нужны). Но с этими платами всё намного проще — нашли производство в России, где их могут собрать. Сроки намного ниже чем в Китае. Тем кто предзаказывал Виртурилку бонусные платы поедут отдельной посылкой/курьером, доставка с нас. Для всех остальных — как обычно, платы в нашем интернет-магазине.

    Про упаковку

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





    А вообще комплект в сборе выглядит примерно вот так



    Про коробочки

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

    Адрес магазина по коробочкам — www.zigo.am/products/virt2real-enclosures/

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







    Программные затыки, нид хелп


    TI для своих процессоров периодически выкладывает так называемый PSP — Platform Support Package. Это набор программных компонентов для функционирования плат на базе их процессоров, например, используемых у нас DM365 семейства DaVinci. В составе PSP имеется проверенный Linux, набор модулей для аппаратного ускорения кодеков и прочеее. Но все официальные PSP базируются на довольно старом ядре, 2.6.32 (и чуть посвежее 2.6.37). Все DSP и плагины GStreamer заточенны под использование только с ядром 2.6.32, а версия 2.6.37 уже не поддерживается, так как там поменялась концепция организации эмбедед видеоподсистемы, которую назвали Media Application . Поэтому GStreamer не умеет работать с источниками видео нового типа. Но помимо PSP фирма TI ещё выкладывает пакет софта под названием DVSDK. В его составе как раз идут модули DSP, а так же куча примеров исходников по работе с кодированием и передачей видео, но про GStreamer — ни слова. А всё-таки с гстримером намного удобнее взаимодействовать, так что у нас не оставалось выбора — надо пилить всё что можно, лишь бы он заработал с новым ядром (соответственно, с новой видеоподсистемой).

    Так как одна эта задача тянет на довольно нехилый проект, было решено сделать финт ушами — портировать старую подсистему на новое ядро, что и было успешно сделано. Сейчас камера уже видится как обычный девайс v4l2, гстример на «ура» кушает отдаваемый ею поток. Но появился один нюанс с одним из модулей DSP (cmem.ko). Модуль до смешного простой, но делает основную работу по трансляции адресов памяти, необходимой для корректной работы аппаратного ускорения. Вот на этом модуле сейчас и плотно засели. Это однозначно получится победить, но всё упирается во время.

    Кстати, вполне возможно что у нас в итоге получится единственная прошивка (и единственный SDK) с новым ядром но с видеоподсистемой, пригодной для работы с видео классическим методом — через GStreamer.

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

    Поэтому имеется несколько вариантов развития событий:

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

    Вариант 2.

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

    Вариант 3.

    Выложить текущую прошивку в том виде как она есть.
    Плюсы — всё работает кроме DSP. Минусы — не работает DSP.

    Мы склоняемся именно к третьему варианту, как наиболее подходящему всем, так что именно так и поступим.

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

    Заключение

    Заключение напишу от своего имени. С тех пор как у меня на руках появились самые первые образцы Виртурилки, я её использовал во всех проектах. Некоторые проекты публиковать нельзя, так что про них молчу. Из публичных — Тачка Бонда, Танковые Бои, танк Т-90. А также куча мелких развлекух типа управляемых тележек, клешни, лодочки и т.д. Руки не дошли опробовать на квадрокоптере, это планируем в ближайшем будущем. Для меня Виртурилка оказалась очень удобна именно для таких штук.

    А теперь мы очень надеемся что Виртурилка и для вас (а не только для Гола, прим. Гол) окажется удобным инструментом для быстрой реализации ваших задумок. Мы очень волнуемся и переживаем за наше детище. Боимся, но ждём комментарии и отзывы. Как положительные, так и отрицательные (куда ж без них).

    Ещё раз — спасибо! Моральная поддержка Хабраюзеров и Хабрагостей нам очень помогала всё это время.


    по теме:
    Официальный сайт virt2real.ru
    Официальный интернет-магазин http://shop.virt2real.ru/ (бывший Микрогонки.ру)
    Официальная Вики (в процессе наполнения) wiki.virt2real.ru
    Официальный Твиттер https://twitter.com/virt2real
    Неофициальный блог http://www.g0l.ru/blog/262

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Из песочницы] Различные методы загрузки ассоциаций в Ruby on Rails

    Rails предоставляют нам 4 различных способа загрузки ассоциаций: preload, eager_load, includes и joins. Рассмотрим каждый из них:

    Preload

    Этот метод загружает ассоциации в отдельном запросе:
    <code class="ruby">User.preload(:posts).to_a
    
    # =>
    SELECT "users".* FROM "users"
    SELECT "posts".* FROM "posts"  WHERE "posts"."user_id" IN (1)
    </code>
    Т.к. preload всегда создает два отдельных запроса, то мы не можем использовать таблицу posts в условии выборки:
    <code class="ruby">User.preload(:posts).where("posts.desc='ruby is awesome'")
    
    # =>
    SQLite3::SQLException: no such column: posts.desc:
    SELECT "users".* FROM "users"  WHERE (posts.desc='ruby is awesome')
    </code>
    А таблицу users – можем:
    <code class="ruby">User.preload(:posts).where("users.name='Neeraj'")
    
    # =>
    SELECT "users".* FROM "users"  WHERE (users.name='Neeraj')
    SELECT "posts".* FROM "posts"  WHERE "posts"."user_id" IN (3)
    </code>


    Includes

    По умолчанию includes действует точно так же, как и preload, но в случае наличия условия по ассоциированной таблице переключается на создание единственного запроса с LEFT OUTER JOIN.
    <code class="ruby">User.includes(:posts).where('posts.desc = "ruby is awesome"').to_a
    
    # =>
    SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "posts"."id" AS t1_r0,
           "posts"."title" AS t1_r1,
           "posts"."user_id" AS t1_r2, "posts"."desc" AS t1_r3
    FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
    WHERE (posts.desc = "ruby is awesome")
    </code>
    Если по каким-то причинам необходимо форсировать применение такого подхода, то можно использовать метод references:
    <code class="ruby">User.includes(:posts).references(:posts).to_a
    
    # =>
    SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "posts"."id" AS t1_r0,
           "posts"."title" AS t1_r1,
           "posts"."user_id" AS t1_r2, "posts"."desc" AS t1_r3
    FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
    </code>

    Eager_load

    Этот метод загружает ассоциации в одном запросе с использованием Left Outer Join, точно так же, как действует includes в сочетании с references.

    <code class="ruby">User.eager_load(:posts).to_a
    
    # =>
    SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "posts"."id" AS t1_r0,
           "posts"."title" AS t1_r1, "posts"."user_id" AS t1_r2, "posts"."desc" AS t1_r3
    FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
    </code>

    Joins

    Создает запрос с использованием INNER JOIN.
    <code class="ruby">User.joins(:posts)
    
    # =>
    SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id"
    </code>
    При этом, загружаются данные только из таблицы users. Кроме того, этот запрос может возвратить дублирующие друг друга записи:
    <code class="ruby">def self.setup
      User.delete_all
      Post.delete_all
    
      u = User.create name: 'Neeraj'
      u.posts.create! title: 'ruby', desc: 'ruby is awesome'
      u.posts.create! title: 'rails', desc: 'rails is awesome'
      u.posts.create! title: 'JavaScript', desc: 'JavaScript is awesome'
    
      u = User.create name: 'Neil'
      u.posts.create! title: 'JavaScript', desc: 'Javascript is awesome'
    
      u = User.create name: 'Trisha'
    end
    </code>

    Результат выполнения User.joins(:posts) в БД с такими данными:
    <code class="ruby">#<User id: 9, name: "Neeraj">
    #<User id: 9, name: "Neeraj">
    #<User id: 9, name: "Neeraj">
    #<User id: 10, name: "Neil">
    </code>
    Избежать повторений мы можем с использованием distinct:
    <code class="ruby">User.joins(:posts).select('distinct users.*').to_a
    </code>
    Если же мы хотим дополнительно получить какие-либо данные из таблицы posts, мы должны внести их в предложение select:
    <code class="ruby">records = User.joins(:posts).select('distinct users.*, posts.title as posts_title').to_a
    records.each do |user|
      puts user.name
      puts user.posts_title
    end
    </code>
    Стоит заметить, что после выполнения метода joins вызов user.posts приведет в созданию еще одного запроса.

    Оригинал статьи

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    IMAP на boost::asio

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

    В нашем случае были также изначальные архитектурные замечания.

    • Поток, обслуживающий реактор, никак не контролировался и при поступлении контрольных сигналов мог произойти race-condition. С другой стороны, останавливать или замедлять этот поток нельзя, поэтому возможные пути обхода выглядели неприемлемыми.
    • Реактор не умел работать в full-duplex режиме. Это ограничивало его использование только интерактивными протоколами, каким является IMAP. Однако между серверами мы часто используем протокол IProto, который подразумевает full-duplex связь.

    Лирическое отступление про IProto: протокол очень простой: заголовок из трёх полей типа uint32_t: команда, номер пакета, длина данных. За счет поля «номер пакета» сервер может отвечать на запросы в любом порядке, а клиент может ждать ответа в асинхронном стиле и слать следующий запрос. В Mail.Ru Group он используется повсеместно — начиная с нашей Tarantool, и заканчивая сервисом антибрутфорса.
    Поэтому было решено сделать тестовую версию, используя boost::asio. В этом посте я расскажу о переезде на реактор boost::asio, о его преимуществах и о подводных камнях, с которыми мы столкнулись.

    Почему выбрали именно boost::asio? Как правило, асинхронное приложение подразумевает не только опрос сокетов при помощи epoll. В реальном приложении еще нужны таймеры, треды, стратегии предотвращения RC, корректная работа с SSL, родная поддержка IPv6. boost::asio позволяет делать это все в C++ стиле естественным образом.

    Процесс переезда

    Заменить реактор оказалось довольно просто. Этому помогло несколько факторов.

    • В старом реакторе точки чтения/записи были строго стандартизованы, т.к. вызывались из самого реактора, поэтому расставить коллбеки чтения/записи оказалось просто. Есть, конечно, исключения, в частности, обработка литералов и команды FETCH, у которой нужно ограничивать размер буфера записи.
    • Таймеры работали отдельно от самого реактора, поэтому он были полностью заменены родным для asio deadline_timer.
    • В качестве стратегии предотвращения RC используется asio::strand.
    • boost::asio использует OpenSSL, которая, как известно, является общепринятым стандартом. Кроме того, скорость шифрования потока у OpenSSL существенно выше, чем у остальных библиотек (пруф).

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

    В целом, увеличение стабильности и отзывчивости сервера было налицо уже в первой релизной версии, что, конечно же, порадовало. Конечно, не все было так радужно — были и некоторые проблемы. Например, с asio::strand, с настройкой правильного самоуничтожения объектов соединения, с «тяжелыми» операциями APPEND, COPY, FETCH, с boost::asio::streambuf, который не любит отдавать память. Но обо всем по порядку.

    Структура сервера

    Структура больше всего похожа на HTTP Server 3 из примеров boost::asio.
    События обслуживаются пулом тредов, который запускает один инстанс io_service::run. Это позволяет достигнуть более высокой отзывчивости сервера, т.к. любой свободный поток может выполнить обработчик события, если он готов к выполнению.

    Состояние соединения с каждым клиентом обслуживается своим экземпляром класса, реализующим базовые функции приёма/передачи/отслеживания таймаутов. Далее от него наследуются классы состояний согласно RFC: неавторизованные, авторизованные. Базовый класс содержит в себе экземпляры классов deadline_timer для отслеживания таймаутов соединения, дескриптор сокета (в нашем случае это asio::ssl::stream, т.к. в нем инкапсулируется SSL-шифрование), asio::strand для предотвращения одновременных срабатываний обработчиков событий (т.к. они являются методами этого же класса, нужно предотвратить race condition).

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

    Различные «тяжелые» операции выполняются по-особому. Надолго блокировать strand нежелательно, при этом команды могут быть достаточно долгими (например, COPY). Поэтому применяется обходной вариант, позволяющий запустить эту работу в безопасном в плане RC режиме, но в тоже время не блокировать strand. При получении команды сервер просто проверяет, что все параметры верны, запоминает их, отключает все события, которые могут вызвать RC, а затем через io_service::post вызывает метод, который, собственно, производит действие. Получается, что действие происходит в deattached-режиме, не мешая своей блокировкой выполнять другие запросы.

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



    Как asio ведет себя под нагрузкой

    Если коротко — прекрасно. Обычно на одном фронтенде около 40 тыс. клиентских соединений. Плюс еще какое-то количество — к внутренним сервисам: базам, хранилищам и т.д. Не все из них контролируются реактором asio, но пока этого достаточно. CPU редко выходит за пределы 10-20%. С памятью не все так гладко: при этом количестве соединений ее потребление на уровне 6-7 ГБ, в основном из-за тяжести некоторых команд протокола и потребления памяти SSL.

    Вероятно, многие слышали о проблеме 10K. Так вот, для asio это абсолютно не проблема, особенно если ваши библиотеки и подсистемы умеют работать в non-blocking режиме. Пожалуй, это самый важный момент приложения на asio и асинхронного приложения вообще. Когда этот момент решен, вы можете обслуживать сотни тысяч соединений, если, конечно, у вас хватит памяти и CPU. Так что я считаю, что в современном мире резонно говорить о проблеме C100K или C1M.

    А на самом деле…

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

    Первое — asio::strand. Для тех, кто не в курсе — это такой хелпер, который умеет оборачивать коллбеки своей логикой; она не даёт вызывать в разных тредах колблеки, которые были обернуты одним экземпляром strand. Таким образом, обеспечивается безопасность обработчиков событий в multithreaded-окружении. Но этот сыр оказался не бесплатным, а дело вот в чём: strand-ы внутри себя используют так называемые «strand implementations», причем их количество зашивается на стадии компиляции. Последние, в свою очередь, содержат mutex-ы. К чему это приводит? Допустим, у нас есть соединения A, B, C, а количество «strand implementations» равно 2. Если в одном из соединений, например A, происходит долгая операция, то соединения B и C в момент аллокации стренда для них могут попасть в тот же implementation, что и А. Тогда все их хендлеры заблокируются, пока А не завершит операцию. В этом смысле простой mutex на хендлерах соединений был бы более эффективным. Осознание этой проблемы пришло далеко не сразу, а решение очень простое — при компиляции проставляем дефайны BOOST_ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION и BOOST_ASIO_STRAND_IMPLEMENTATIONS, равный ожидаемому количеству соединений. Почему-то такая особенность не документирована нигде, кроме как в самом коде strand_service. Конечно, если все используемые протоколы у вас неблокирующие и приложение true-асинхронное, такая проблема вряд ли будет актуальна, но в нашем случае есть legacy библиотеки, работающие в блокирующем режиме, поэтому (пока) приходится искать обходы.

    Также есть кое-какие особенности, связанные с буферами чтения/записи. Если использовать asio::streambuf, нужно понимать, что данный буфер не любит отдавать память — с этим приходится считаться и делать какие-то обходные телодвижения. Несколько расстраивает, что нет родного конкурентного буфера записи. Для протоколов вроде нашего IProto это было бы очень полезной возможностью — протокол подразумевает очень большое количество небольших пакетов. Еще из минусов — нет защиты от RC при записи в сокет, поэтому не стоит в режиме SSL (да и в обычном тоже!) делать параллельные async_write; опять же нужно организовывать очередь, либо механизм переключения буферов записи, либо просто каким-то способом предотвращать параллельные вызовы. А здесь опять возникают дополнительные проблемы: если пир пропадет, буфер записи может продолжать расти, пока текущий async_write не поймет, что пира больше нет. Это может скушать вашу память, что, конечно же, опять-таки отразится на максимуме открытых соединений.

    Возможно, это очевидный для многих факт, но все-таки хотелось бы подчеркнуть его отдельно: 10 тыс. соединений «наружу» — это не то же самое, что 10 тыс. соединений на каком-либо внутреннем сервисе, куда ходят только «свои». В первом случае могут произойти просто невероятные вещи, с которыми и представляет наибольшую сложность. Это могут быть странные клиенты, которые умудряются отключаться до завершения SSL handshake. Могут быть и жутко медленные, которые закачивают к вам письмо размером 40 МБ со скоростью 256 Кбит/с. Звучит просто, однако команда APPEND принимает тело письма в качестве литерала; это означает, что пока письмо не закачано, команда еще не отдана и должна так или иначе находиться в памяти, а память, как известно, не резиновая. В случае с командой FETCH все наоборот: если у клиента скорость приёма медленная, а вы хотите отправить 1 МБ, этот кусок данных находится у вас в памяти до тех пор, пока он не отправится.

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

    Заключение, планы по развитию сервера

    В целом мы довольны. Сервис стал работать стабильнее, обрабатывать больше соединений, гораздо меньше крэшиться.
    Дальнейшее развитие сервера неминуемо — мы планируем улучшать стабильность, расширять поддержку rfc extensions, в том числе IDLE; думаю, boost::asio легко поможет нам в этом. Пока трудно представить, сколько соединений могло бы одновременно находиться в состоянии IDLE, но, полагаю, очень много. Возможно, эффект от этого будет не так уж велик, так как многие мобильные клиенты (а сейчас их большинство) не умеют IDLE. Но сделать это на asio будет весьма просто, поэтому со стороны IMAP-сервера это вовсе не сложная доработка.
    Также на подходе новые внутренние сервисы, которые по своей природе асинхронны, а общение с ними происходит по нашему любимому протоколу IProto, что позволит меньше блокироваться и, следовательно, обрабатывать запросы быстрее.
    Есть вопросы? Задавайте! Есть полезный опыт внедрения? Делитесь в комментариях!

    Альберт Галимов,

    Программист группы backend разработки Почты


    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [NES] Пишем редактор уровней для Prince of Persia. Глава первая. Знакомство

    Disclaimer
    В детстве, как и у многих, родившихся в 80-х, у меня была приставка Dendy. Клон японской FamiCon, подаренный нам добрыми китайцами, и распространяемый небезызвестной Steepler, раскрасил в яркие цвета детство многих из поколения 80-х. Раз за разом, проходя полюбившиеся мне игры вдоль и поперек, находя все возможные секреты (причем, зачастую, без книжек с громкими заголовками в духе «Секреты и прохождения 100500+1 игр», ценность которых стремилась к нулю), мне хотелось играть в них еще и еще, но с новыми уровнями, новыми секретами и новыми возможностями.

    Некоторые игры предусматривали встроенный редактор уровней (например, Battle City, Fire'n'Ice aka Solomon's Key 2), но большинство из них, разумеется, таковой возможности не предоставляли. Хотелось сыграть (естественно!) в новый Super Mario Bros (о, как я любил и ненавидел китайцев, выпустивших картридж 99...9 in 1, в котором были уровни A-1, B-1,… Z-1, которые невозможно было пройти, или которые представляли собой дубли оригинальных уровней, но с измененными текстурами), Duck Tales 1, 2 и многие другие.

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

    Между тем, редакторы на одни игры находились чуть ли не по первым ссылкам в гугле, на другие же были запрятаны либо где-то далеко (но находились таки), либо отсутствовали вовсе. Найдя редакторы для большинства любимых мной игр, я никак не мог найти редактор для Персидского принца. Да, есть редакторы для DOS-версии, есть для SNES, но моя родная, — NES-версия, была обделена таким сокровищем.

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

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

    Начал я… Впрочем, перед тем, как я начну рассказывать далее, предостерегу:
    Не рекомендуется лезть под кат профессионалам. Там рассматриваются «живодерские» методы новичка! Работа Вашей нервной системы может быть необратимо нарушена! Я предупредил.


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

    NES-заголовок
    Это первое, что лежит на поверхности. С него и начнем.
    Заголовок имеет размер в 16 байт, где помимо сигнатуры имеется техническая информация о ROM-файле. ROM-файл сам по себе — это совокупность данных и технической информации в одном файле. Заглянем внутрь заголовка.
    4E 45 53 1A 08 00 21 00 00 00 00 00 00 00 00 00

    4 байта: Сигнатура NES->;
    1 байт: Количество 16 кБ PRG-ROM банок;
    1 байт: Количество 8 кБ CHR-ROM банок;
    2 байта: Флаги;
    1 байт: Количество 8 кБ PRG-RAM банок;
    2 байта: Флаги;
    Оставшийся хвост — нули.

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

    Из заголовка мы выясняем, что у нас Mapper #2 (байт с номером маппера составляется из половинок шестого и седьмого байтов) и 8 16 кБ PRG-ROM банок. Все остальное отсутствует.

    Из документации следует, что PRG-ROM банки — это собственно код + произвольные данные, которые будут использованы непосредственно CPU. CHR-ROM банки — это данные для видеоподсистемы (PPU). CPU к ним непосредственно обратиться не может.
    Как же мы получаем изображение, если у нас нет ни одного CHR-ROM? Очень просто: в PRG у нас хранятся данные, которые все время копируются в память PPU. Неудобно? Да. Но над этими данными у нас, в некотором смысле, больше власти.

    Далее мы выясняем, что Mapper #2 на самом деле подразумевает несколько различных мапперов, одинаковых по функциональности, но различаемых по структуре: UNROM и UOROM, объединенных по названию в UxROM. Разница лишь в количестве PRG-ROM банок: в первом 8 банок, во втором — 16. Для любого из них последний банк фиксирован в конце оперативной памяти ($C000-$FFFF), а оставшиеся 7 (или 15 для второго случая) могут переключаться в область памяти $8000-$BFFF.
    Это все техническая информация, которая, на данный момент ни о чем толковом нам не говорит.

    Запасаемся консервами
    Итак, мы можем разбить ROM-файл на 9 составляющих: Заголовок и 8 банок. Заголовок редактировать смысла нет, т.к. там хранится информация для программы-эмулятора, а как редактировать банки мы не знаем. Во-первых, в банках нет какой-либо строгой структуры (как, например, в PE-формате, где код и ресурсы лежат в своих секциях) и данные могут быть перемешаны хаотично с кодом. Может нам и вовсе не повезло и данные для построения уровней формируются исполняемым кодом.

    Но, пока прикинем варианты, как бы мы могли достать то, что нам нужно из цельных кусков бинарной каши:
    1. Самый сложный, но и самый универсальный: последовательный реверс кода отладчиком. С помощью этого метода мы точно доберемся до того, что нам нужно, по пути получая бонусы в виде дополнительной информации о том, как построен код. Минусы очевидны: на реверс мы потратим уйму времени, но это еще полбеды, ведь мы пока еще ничего не знаем, а значит на изучение ассемблера и различных «трюков» программирования на нем мы потратим 90% времени. Т.е. КПД будет около 10%. Мало;
    2. Изучение оперативной памяти, а затем отладка по точкам останова обращения к памяти (рассмотрим чуть ниже). Этот способ уже лучше. Памяти для изучения у нас сравнительно немного: из 64 кБ имеющейся памяти у нас половина уходит на банки из ROM-файла, половина от этой половины — либо зарезервировано, либо используется портами IO. И, наконец, оставшаяся половина бьется на четыре части по 4 кБ. Первая часть — собственно оперативка, используемая кодом, а оставшиеся три — зеркала первой части. Таким образом, на изучение у нас остается 4 кБ памяти, которую вполне можно изучить глазами прямо наживую. КПД способа повыше, т.к. мы будем иметь перед глазами живые данные, которые мы можем менять прямо во время выполнения и смотреть тут же на результат;
    3. Изучение считанных данных. В момент перехода на другой уровень или перехода в другую комнату изучаем данные, которые были считаны из ROM-файла. Как мы помним, в Prince of Persia каждый уровень делится на комнаты, между которым он бегает;
    4. «Живодерский» способ — «Брутфорс»: последовательно меняем по одному байту, скриншотим результат, а зачем изучаем кучу скриншотов.

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

    Вооружимся инструментами:
    • Любимый ЯП для написания вспомогательный утилит. Может быть какой угодно. Я использовал C++ в составе VS2010;
    • Эмулятор с отладчиком. Я использовал версии из разных веток FCEUX-эмулятора. FCEUX и FCEUXDSP. У первого простенький топорный отладчик, который умеет совсем простые вещи. У второго очень мощные инструменты по отладке и изучению памяти, но он, к сожалению, часто падал, поэтому в простых случаях я прибегал к первому;
    • Любой шестнадцатеричный редактор. Я использовал WinHEX, который позволяет, не сохраняя файл, запустить его на выполнение (редактируем любой байт и жмем Ctrl+E).
    • Для справки по коду можно использовать IDAPro с загрузчиком NES. Можно использовать загрузчик от cah4e3. Но чудес от нее не ждите, т.к. банки в процессе выполнения меняются динамически, и правильный код будет только из последней банки.
    Перед тем, как приступать, посмотрим на то, что же такое UxROM:
    Вообще говоря, Mapper — это с точки зрения эмулятора алгоритм, а с точки зрения железа некий контроллер, который занимается переключением банок в памяти.
    Во-первых: Зачем он это делает?
    Во-вторых: Как он это делает?

    На первый вопрос ответ простой: оперативной памяти, которую может адресовать процессор, немного — всего 64 кБ, причем туда надо впихнуть не только код и данные, но и порты ввода/вывода, а так же кучу других вещей (вроде энергонезависимой памяти, куда сохраняются промежуточные результаты некоторых игр). Нашли простое решение: по мере выполнения кода не все данные в памяти требуются для работы, поэтому их можно просто исключить, а на их место поставить более важные в данный момент времени. Рядом с ROM-памятью на картридже поставили контроллер, который по команде в адресную память отображает нужный кусок. В зависимости от сложности игры эти контроллеры различались своей начинкой. Китайцы же это дело вовремя подхватили и напридумывали много разных (адекватных и не очень) мапперов. Благодаря этому у нас появилось большое количество многоигровок.

    Во втором вопросе мы рассмотрим только работу маппера UxROM, так как остальные нам сейчас неинтересны. Маппер берет последний банк (#07 или #0F), помещает его по адресам $C000-$FFFF и больше не трогает. Все остальные банки включаются по мере надобности после записи (в общем случае) по любому адресу из пространства $C000-$FFFF номера банка (#00-#06 или #00-#0E). Но правильно это делается следующим образом: по адресу $FFF0+N записывается N, где N — номер банка, и в итоге по адресам $8000-$BFFF мы видим содержимое нужного банка.

    Рубим банку топором. Способ №4.
    Для этого была написана небольшая утилита, которая меняла один байт (простой инкремент: Byte++), сохраняла в отдельный файл, далее запускала в эмуляторе полученный ROM, выполняла скриншот и закрывала эмулятор.
    Разумно было бы сократить количество скриншотов, т.к. изучить over 130.000 скриншотов даже бегло было бы сложно.

    Поскольку у нас только PRG-ROM банки, то в каких-то из них наверняка хранятся и тайлы, которые нам неинтересны. Их мы и попробуем исключить.
    Берем любой тайловый редактор, открываем в нем ROM-файл. Я использовал Tile Layer Pro — это довольно таки древняя программа, но дело свое знает. Выглядит она примерно так (на скриншоте тайлы из игры Final Fantasy). В статусной строке окна программы указано смещение каждого тайла. Мы можем прокрутить окно с данными до того момента, где очевидно заканчиваются тайлы и начинаются «мусорные» с точки зрения графики данные. Прокрутив, выясняем, что первые две банки — это графика. Их мы пропускаем и остается 6 банок. Уже «всего» 96 кБ. Сложно, но все же полегче.

    Ну что ж. Как этим способом мы найдем нужные нам данные? Очень просто: бегло просматривая скриншоты мы увидим, что на некоторых из них у нас последовательно меняются блоки в комнатах. Комната состоит из 10х3 блоков, соответственно на 30 скриншотах подряд у нас должны (но не обязаны!) будут изменяться рядом стоящие блоки на какие-нибудь другие: например, «бетонный» блок может поменяться на колонну или что-нибудь еще.

    Запускаем утилиту по перебору где-нибудь в сторонке, а сами приступим к изучению считанных из ROM данных.

    Режем крышку банки тесаком. Способ №3.
    Этот способ аналогичен предыдущему, но мы существенно сокращаем объем данных для изучения. Как?
    В FCEUXDSP есть инструмент, который сохраняет считанные данные в соседний файл. Между нажатиями кнопок Start и Pause считанные данные помещаются в файл ровно в то место, в котором они хранятся в оригинальном. Таким образом, мы можем открыть диалог фиксации данных, нажать Start, в игре перебежать из одной комнаты в другую, нажать Pause, и так же как и в предыдущем пункте, изучить зафиксированные данные. Этих данных будет существенно меньше. По сути сам код нам покажет то, на что следует обратить внимание. А перебрать сотню-другую байт труда не составит даже вручную.

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

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

    Для начала выделим несколько моментов из документации:
    1. Адресация может быть непосредственная регистр<->память (IMM): LDA $00; STA $00;
    2. Прямая с участием индексных регистров: регистр<->память+INDEX: LDA $0000, X; STA $0000, Y;
    3. Косвенная с участием индексных регистров: регистр<->указатель+INDEX: LDA ($00), X; STA ($00),Y;
    В косвенной адресации процессор извлекает из двух ячеек (в пределах первой страницы памяти $00-$FF) 16-битный указатель, прибавляет к нему значение индексного регистра, и затем уже работает с ячейкой по полученному таким образом адресу.

    Отсюда составим следующие соглашения по псевдокоду:
    • Переменные обозначим как $XXXX (где XXXX — ее адрес);
    • Прямую адресацию обозначим как #XXXX[Y] (где XXXX — адрес, от которого адресуем);
    • Косвенную адресацию обозначим как $XXXX[Y] (полная аналогия с массивами в Си);
    • Все процедуры у нас имеют одинаковый вид: char sub_XXXX() { }. Так как в NES нет каких-либо соглашений по передаче аргументов, то аргументов у нас не будет. Какие-либо данные, как правило, передаются либо через регистры, либо через переменные.
    • Регистры имеют оригинальные имена (A, X, Y).
    • Восьмибитные числа будем записывать как #XX в HEX
    Возьмем простой код переключения банок:
    <code>$F2D3:84 41 STY $0041 = #$00
    $F2D5:A8 TAY
    $F2D6:8D D1 06 STA $06D1 = #$06
    $F2D9:99 F0 FF STA $FFF0,Y @ $FFF0 = #$00
    $F2DC:A4 41 LDY $0041 = #$00
    $F2DE:60 RTS
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    </code>
    Попробуем перевести построчно:
    <code>char switch_bank() // передаем номер включаемого банка в регистре A
    {
        $0041 = Y; // сохраняем Y
        Y = A;
        $06D1 = A; // сохраняем номер включаемого банка
        #FFF0[Y] = A; // включаем банк путем записи в порт $FFF0+N числа N (где N - номер включаемого банка)
        Y = $0041; // восстанавливаем содержимое Y
        return A;
    }
    </code>

    Теперь возьмем код посложнее:

    <code>;; процедура копирования тайла из оперативной памяти в память PPU
    $F302:20 D3 F2 JSR $F2D3
    $F305:8E 06 20 STX $2006 = #$41
    $F308:A9 00 LDA #$00
    $F30A:8D 06 20 STA $2006 = #$41
    $F30D:A2 10 LDX #$10
    $F30F:A0 00 LDY #$00
    $F311:B1 17 LDA ($17),Y @ $020E = #$03
    $F313:8D 07 20 STA $2007 = #$00
    $F316:C8 INY
    $F317:D0 F8 BNE $F311
    $F319:E6 18 INC $0018 = #$02
    $F31B:CA DEX
    $F31C:D0 F1 BNE $F30F
    $F31E:4C 10 D0 JMP $D010
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    </code>

    Первый этап перевода:
    <code>char sub_F302()
    {
                sub_F2D3(); // switch bank. Bank counter in A register
              // $2006 – PPU Address register
              // $2007 – PPU data write
              // В $2006 записываем адрес в видеопамяти 
              // (старший байт, затем младший)
              // 2007 после чего в регистр записываем данные
              // в PPU. После каждой записи адрес PPU
              // автоматически увеличивается на 1.
                $2006 = X; // старший байт адреса 
                $2006 = #00 // младший байт адреса 
                X = #10;
    label_F30F:
                Y = #00;
    label_F311:
              // в ячейках $0017:$0018 лежит указатель 
              // , на данные, которые будем записывать в PPU
                $2007 = $0017[Y];
                Y++;
                if ( Y != #00 ) goto label_F311;
                $0018++;
                X--;
                if ( X != #00 ) goto label_F30F;
                return sub_F2D3(#05);  // включаем 5-ый банк
    }
    </code>

    И последний этап перевода:
    <code>void WriteDataIntoPPU(char Bank, char PPULine)
    {
                switch_bank(Bank); // switch bank.
                PPUADDRESS = PPULine; // старший байт адреса 
                PPUADDRESS = #00; // младший байт адреса 
                for(X = #10; X > 0; X--)
                {
                            for(Y = #00; Y <= #FF; Y++)
                            {
                                        PPUDATA = $Tiles[Y];
                            }
                            $Tiles += #100; // переходим на следующую строку 
                }
                return switch_bank5();
    }
    </code>
    В два простых этапа мы переписали сложночитаемый (для новичка) ассемблерный листинг в понятный код. Я не рассматривал процедуру switch_bank5, там банальный код присвоения регистру A числа #05, а затем вызов процедуры переключения банка sub_F2D3. Для выработки автоматизма при переводе кода в читаемый мне хватило пары-тройки процедур, далее все становится намного проще. После того, как у меня скопилось с десяток 5-7 кБ текстовых файлов, переводить код уже стало попросту не нужно — все стало происходить само собой в голове.

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

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

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Nimbus Screen Capture — Снимите это немедленно!

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

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

    image



    Что умеет Nimbus? Функций у него немало, однако перечислим наиболее существенные:

    • Захватывать весь экран или его часть;
    • Снимать всё окно браузера, вместе с панелями (только в Chrome);
    • Редактировать скрины (менять размер, кадрировать, зарисовывать часть картинки);
    • Добавлять к снимку различные графические объекты (стикеры, стрелки);
    • Создавать собственный рисунок с нуля;
    • Сохранять скриншоты в форматах JPG, BMP, PNG;
    • Отправлять готовые скрины в Google Drive.

    Поддерживается пост-едит элементов, т.е можно изменять элементы уже после их нанесения. Снимать скриншоты можно, как через кнопку аддона, так и используя хоткеи. На сегодня поддерживается отправка скринов в Google Drive, однако скоро мы добавим поддержку собственного сервиса. В планах также Imgur.

    image

    Доступны расширения для браузеров Chrome, Opera (для версий 15 и выше) и Firefox . В скором времени будет мобильное приложение для Android. Русификация аддонов также в самом разгаре.

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

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Клиент Яндекс.Диска для Linux. Консольный

    Сегодня мы представляем долгожданный клиент Яндекс.Диска для Linux. Можно было бы даже сказать «специально для Хабрахабра», так как ни одно упоминание Диска здесь не обходилось без вопросов о клиенте для Линукса.

    У него есть вся основная функциональность, которая есть у клиентов для OS X и Windows, и даже больше (симлинки!), и одна особенность — он консольный.

    image

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


    Установить его можно здесь. Сразу после установки пакета в терминале появится команда yandex-disk, через которую в дальнейшем и идет общение с облаком Яндекса. После этого нужно вручную запустить команду setup.

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

    Команды

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

    • Sync запустит демон, синхронизирует все, находящееся в папке Диска, и остановит демон.
    • Start сделает то же самое, но без остановки демона после завершения синхронизации. При использовании start демон остается запущен и все изменения, происходящие в папке Диска, будут синхронизироваться автоматически.
    • Введя в терминале stop, можно в любой момент остановить запущенный демон, если он вам мешает.
    • Командой status можно узнать, в каком статусе находится ядро синхронизации.
    Работать с папкой диска можно как из терминала, так и из Nautilus'a.

    Что умеет

    Консольный клиент позволяет поделиться файлом или папкой с помощью команды publish (если файл находится не в папке диска, перед публикацией он будет туда скопирован). Ссылка будет доступна в терминале, и любой человек, пройдя по ней, сможет посмотреть или сохранить себе опубликованный вами файл или папку. Если случайно был опубликован не тот файл, с помощью команды unpublish можно закрыть доступ к публичному объекту.

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

    Опция read-only позволит менять файлы локально, без заливки их в облако. При возникновении конфликтов с локальными изменениями, последние будут сохранены в переименованных файлах, а изменения из облака будут синхронизированы. Опция overwrite будет перезаписывать локально измененные файлы в режиме read-only.

    Не можем не похвастаться самым интересным нововведением в ядре синхронизации — отныне мы поддерживаем синхронизацию симлинков! Если возникнут трудности и вопросы в использовании консольного клиента команды man и help просто и доступно помогут в них разобраться.

    Как сделан

    Чтобы в будущем код можно было использовать для реализации клиентов под разные ОС, было принято решение писать его на C++. Специфичные для разных операционных систем куски кода мы вынесли в отдельные функции или классы, а под каждую платформу писали свою реализацию. В качестве основных кроссплатформенных библиотек мы взяли Boost, OpenSSL и JsonCpp, а системой контроля версий стал git. Клиент под Linux собирался с помощью autoconf. Код писался и отлаживался в связке KDevelop + консольный gdb, либо в Qt Creator'е (в зависимости от предпочтений разработчика).

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

    Как работает

    Консольный клиент состоит из двух частей: демона и клиента. Общаются они посредством текстовых пакетов содержащих json-сообщения, посылаемые через сокеты (на Linux и Mac OS X используются unix-domain сокеты). Асинхронная работа реализована с помощью библиотеки boost::asio. Синхронизация доступа к данным реализуется через boost::asio::io\_service::strand, что позволяет не думать о проблеме одновременного доступа к данным нескольких потоков, а также исключает появление deadlock-ов.

    Для локализации мы используем библиотеку boost::locale. Текст внутри клиента закодирован в utf-8 и по необходимости преобразовывается в специфичном для каждой операционной системы коде. Мониторинг файловой системы для Linux использует inotify, прекрасно вписыващийся в асинхронную работу boost::asio.

    Как устроена синхронизация

    Синхронизация — сердце Яндекс.Диска, его ключевая возможность. Задача синхронизации файлового дерева с облаком делится на несколько независимых частей.

    1. Мониторинг файловой системы. Ядро синхронизации Яндекс.Диска проектировалось и создавалось как переносимая абстракция, способная выполнять поставленные задачи на всех поддерживаемых платформах. Но такая проблема, как мониторинг файловой системы не реализуется ни стандартной библиотекой C++, ни даже такими монстрами как boost. Более того, даже используя «родное» API операционной системы, мы получаем набор событий, специфический для каждой платформы.

    Для мониторинга файловой системы был спроектирован интерфейс «наблюдателя», способного следить за событиями в определённой директории и возвращающего список событий, произошедших в ней. Причём для каждой поддерживаемой платформы набор этих событий отличается. Например, Mac OS X способна сообщить только о факте какого-то изменения в одной из дочерних директорий без детализации. А вот Windows и Linux возвращают полный набор, включая создание, удаление, модификацию и перемещение объектов. Хотя практика показывала, что событиям на платформе Windows доверять не стоит и самым надёжным вариантом остаётся листинг директории после получения оповещения.

    2. Индексация локальных файлов и директорий. Для контроля целостности и реализации дельта-обновления файлов ядро синхронизации Яндекс.Диска использует дайджесты — наборы контрольных сумм файла и отдельных его частей. Для всего файла мы рассчитываем стойкий хэш SHA-256 и набор менее стойких сумм для отдельных блоков. Каждый файл, находящийся в папке Яндекс.Диска и не попадающий в список исключений, должен быть проиндексирован. Но вычисление хэша SHA-256 -достаточно дорогая операция, а расчёт хэшей при каждом запуске ПО был бы непростительной тратой ресурсов. Поэтому после того, как завершается индексация файла, ядро синхронизации сохраняет полученный дайджест в «банке» — специальном хранилище, находящемся в служебной директории Яндекс.Диска. Для поиска дайджестов в хранилище используется уникальный идентификатор файла — inode (размер и время последнего изменения). К сожалению, подобный подход не лишён недостатков. Например, многие файлы-криптоконтейнеры сохраняют время последней модификации неизменным даже после записи.

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

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

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

    4. Получение оповещений об изменении облачной файловой системы. Синхронизация файлов в реальном времени требует своевременного получения оповещений об изменениях, произошедших с файлами в облаке. Можно было бы использовать периодический опрос сервера клиентами, но, оценив возможное количество клиентов, мы пришли к выводу, что такой подход окажется слабо масштабируемым и приведёт к быстрой перегрузке инфраструктуры сервиса. После недолгих поисков мы остановились на протоколе XMPP. Одна из его реализаций уже долгое время работает в Яндексе. Она была разработана командой, которая позже занимались созданием сервера WebDAV для проекта Яндекс.Диск, поэтому сложностей с интеграцией этого протокола не возникло.

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

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

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

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

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

    Все эти задачи выполняются одновременно, накладывая дополнительные требования на качество синхронизации параллельных процессов и распределение ресурсов внутри ядра синхронизации Яндекс.Диска. Если у вас ещё нет Я.Диска, завести его можно здесь, а установить для Linux — здесь: repo.yandex.ru/yandex-disk.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Измеряем качество поиска в Почте

    В январе в этом посте я рассказывал о полнотекстовом поиске в Почте Mail.Ru.

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

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

    image

    Основной параметр качества поиска – это его скорость. Ее удобнее всего измерять на стороне фронтенда примерно вот таким образом:

    <code class="perl">$mailsearch_start = Time::HiRes::time();
    $answer = MailSearch::Query($request);
    $mailsearch_end = Time::HiRes::time();
    </code>


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

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

    image
    Рисунок 1. Упс! Похоже, выкатили что-то не то…

    Во-вторых, нужен также и «суточный» график, который позволяет обнаружить более глубокие и менее заметные на первый взгляд проблемы. К примеру, если перестроение индексов происходит слишком редко, то будет постоянно накапливаться некоторый «долг» — определенный объем не проиндексированных данных, по которым возможен только последовательный поиск. Этот «долг» будет виден на графике как медленная деградация по скорости в течение нескольких дней или недель (рисунок 2). Подобное поведение графика – сигнал к тому, что стоило бы пересмотреть политику работы планировщика индексаций в сторону того, чтобы индексировать чаще.

    Также этот график оказался для нас очень полезным при переходе со старого поискового движка на новый. Он позволил четко ответить на вопрос: «А стало ли лучше с новым поиском?». Полная переиндексация сервера обычно занимает несколько дней, и суточный график показывает, как за это время поиск постепенно ускорялся вплоть до разницы в 2,5 раза (рисунок 3).

    image
    Рисунок 2. Копим «долг» по индексации. Повод задуматься…

    image
    Рисунок 3. Переходим на новый поисковый движок.

    Следующим стоит отметить график количества поисковых запросов. Данный график сам по себе, без анализа других данных, исследовать трудно. Например, уменьшение количества поисковых запросов может свидетельствовать о двух противоположных вещах:
    1. Пользователи чаще стали находить искомое с первой попытки (хорошо, см. рисунок 4)
    2. Пользователи вообще перестали находить искомое (плохо)

    image
    Рисунок 4. В данном случае стали чаще находить искомое с первой попытки.

    Важным параметром качества поиска является количество запросов с пустым результатом. В среднем оно равно 30%, большая часть таких запросов – это постоянно открытая страница «все непрочитанные» у многих пользователей (ожидание прихода нового письма). Резкий рост данного показателя может свидетельствовать о фатальной ошибке в поиске (при превышении данным показателем некоторого порогового значения имеет смысл слать SMS-уведомление разработчикам и системным администраторам, так как подобные ошибки необходимо устранять за минимальное время, см. рисунок 5).

    image
    Рисунок 5. Проявилась какая-то проблема… Время слать SMS.

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

    image
    Рисунок 6. Качество поиска улучшилось – увеличилось количество переходов.

    Также имеет смысл измерять количество «уточняющих» поисковых запросов. Уточняющим запросом с большой долей вероятности можно считать поисковый запрос, выполненный с открытой страницы результатов поиска. Данный вывод обусловлен предположением, что после того как пользователь попробовал что-то найти, но результаты поиска его не устроили, он решил повторить поиск, но как-то «по-другому», с другим запросом. Таких запросов в среднем 1-3%. Рост данного показателя свидетельствует о том, что поиск перестал находить что-то из того, что ранее находилось успешно (рисунок 7).

    image
    Рисунок 7. Лишние 3% повторных запросов.

    Развивая тему «уточняющих» поисковых запросов, стоит отметить, что имеет смысл измерять также и количество «перелистываний» результатов поиска. Рост этой величины может служить свидетельством, например, того, что результирующая выборка слишком велика. Таких запросов в среднем 1-2%. Большая часть из них обусловлена естественной необходимостью иногда искать старые письма, листать «глубоко» по времени. Рост данного показателя свидетельствует о том, что что-то «лишнее» попало в результаты и отодвинуло назад (на следующие страницы) релевантные письма. Падение данного показателя, наоборот, определенно хороший признак, ведь пользователи начинают находить искомое на первой странице результатов поиска (рисунок 8).

    image
    Рисунок 8. Теперь все нужное на первой странице, и листают реже.

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

    image
    Рисунок 9. Переработали раскраску сниппетов, и среднее время перехода упало.

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

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

    Дмитрий Калугин-Балашов
    программист команды Почты Mail.Ru


    P.S.: Все графики сделаны лично мной руками в Excel по мотивам реальных событий.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Перевод] Паттерн Стратегия на Javascript

    От переводчика:
    Я собрался изучить новый для меня паттерн Стратегия, но не нашёл толкового русского описания его реализации на javascript. Статья на wiki пугает своей сложностью, а наглядность примера оставляет желать лучшего. По этому и взялся за перевод этой статьи, одновременно разбираясь, что же из себя представляет данный паттерн.
    Спойлеры и текст, выделенный серым, являются моими комментариями.
    Далее мы разберём примеры того, как я использую СТРАТЕГИЮ в Javascript, и как он используется реальной библиотекой, для разбиения её на небольшие части.

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

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

    В реализации СТРАТЕГИИ, обычно используются два участника:
    • Стратегия — объект, который инкапсулирует алгоритм.
    • Клиент (или Контекст) — объект, который может использовать любую стратегию в стиле plug-and-play «включил и работай».
    Здесь и далее:
    СТРАТЕГИЯ — сам паттерн.
    Стратегия — отдельная реализация алгоритма.

    Далее мы разберём примеры того, как я использую СТРАТЕГИЮ в Javascript, и как он используется реальной библиотекой, для разбиения её на небольшие части.

    Стратегия как функцияВстроенный класс FUNCTION обеспечивает отличный способ для инкапсуляции алгоритма. А это значит что функции могут быть использованы в качестве стратегий. Просто передайте функцию клиенту и убедитесь, что он клиент её использует.

    Проиллюстрируем это на примере. Допустим, мы хотим создать класс Greeter. Его задача — приветствовать людей. А так же мы хотим, чтобы Greeter умел приветствовать их по-разному. То есть, нам нужно несколько разных реализаций алгоритма. Для этого мы создадим различные стратегии приветствия. Здесь и далее, под алгоритмом подразумевается приветствие.
    <code class="javascript">// Greeter - класс объектов, которые могут приветствовать людей.
    // Он может выучить различные способы приветствия через стратегии
    var Greeter = function(strategy) {
        this.strategy = strategy;
    };
     
    // Greeter содержит функцию greet,
    // которая будет использоваться для приветствия людей
    // через стратегии, переданные в конструктор
    Greeter.prototype.greet = function() {
        return this.strategy();
    };
    
    // Так как функция инкапсулирует алгоритм,
    // она отличный кандидат на роль стратегии
    
    // Немного стратегий:
    var politeGreetingStrategy = function() {
        console.log("Hello.");
    };
     
    var friendlyGreetingStrategy = function() {
        console.log("Hey!");
    };
     
    var boredGreetingStrategy = function() {
        console.log("sup.");
    };
     
    // Давайте используем их!
    var politeGreeter = new Greeter(politeGreetingStrategy);
    var friendlyGreeter = new Greeter(friendlyGreetingStrategy);
    var boredGreeter = new Greeter(boredGreetingStrategy);
     
    console.log(politeGreeter.greet()); //=> Hello.
    console.log(friendlyGreeter.greet()); //=> Hey!
    console.log(boredGreeter.greet()); //=> sup.
    </code>
    В приведенном выше примере мы создали клиент Greeter и три различных стратегии. Очевидно, что Greeter знает, как использовать алгоритм, но понятия не имеет о том, что у него под капотом.

    Но для сложных алгоритмов, функции зачастую бывает недостаточно. В этом случае, лучше использовать СТРАТЕГИЮ в ООП стиле.

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

    Рассмотрим это на примере.
    подразумевается, что перед примером распологается этот код.
    <code class="javascript">var Greeter = function(strategy) {
        this.strategy = strategy;
    };</code>
    <code class="javascript">// Мы можем использовать силу Прототипов в Javascript
    // для создания классов, которые ведут себя как стратегии
    
    // Здесь мы создаём абстрактный класс,
    // который будет служить в качестве интерфейса для всех наших стратегий.
    // Впринципе он не необходим, но полезен в целях документирования
    var Strategy = function() {};
     
    Strategy.prototype.execute = function() {
        throw new Error('Strategy#execute needs to be overridden.')
    };
    
    // Как и в примере выше мы хотим создать стратегии приветствия
    // Давайте создадим для них подкласс из класса `Strategy`.
    // Обратите внимание, что родительский класс требует,
    // что бы дочерние переопределяли метод `execute`
    var GreetingStrategy = function() {};
    GreetingStrategy.prototype = Object.create(Strategy.prototype);
    
    // Определим метод `execute`, который входит в состав публичного интерфейса
    // для объектов класса `Strategy` и дочерних ему.
    // Обратите внимание, что он определён через два других метода.
    // Этот паттерн называется Шаблонный метод (Template Method).
    // Вы увидете его преимущества немного позже.
    GreetingStrategy.prototype.execute = function() {
        return this.sayHi() + this.sayBye();
    };
     
    GreetingStrategy.prototype.sayHi = function() {
        return "Hello, ";
    };
     
    GreetingStrategy.prototype.sayBye = function() {
        return "Goodbye.";
    };
    
    // Теперь мы можем попробовать нашу стратегию.
    // Только сперва потребуется чуть-чуть модернизировать класс `Greeter`.
    Greeter.prototype.greet = function() {
        return this.strategy.execute();
    };
     
    var greeter = new Greeter(new GreetingStrategy());
    greeter.greet() //=> 'Hello, Goodbye.'
    </code>
    Мы определили Strategy как объект (или класс) с методом execute. Клиент может использовать любую стратегию, которая соответствует этому классу.

    Обратите внимание на GreetingStrategy. Самое интересное находится в переопределении метода execute. Он зависит от других методов этого класса. Теперь объекты, унаследовавшие этот класс, могут изменять отдельные методы, такие как sayHi или sayBye, без изменения основного алгоритма. Этот паттерн называется Шаблонный метод и он прекрасно сочетается со СТРАТЕГИЕЙ.

    Давайте посмотрим, как.
    <code class="javascript">// Так как GreetingStrategy#execute определён через другие методы.
    // Мы можем создать подклассы, в которых они будут переопределены,
    // при этом не затрагивая основной алгоритм (метод `execute`)
    
    var PoliteGreetingStrategy = function() {};
    PoliteGreetingStrategy.prototype = Object.create(GreetingStrategy.prototype);
    PoliteGreetingStrategy.prototype.sayHi = function() {
        return "Welcome sir, ";
    };
     
    var FriendlyGreetingStrategy = function() {};
    FriendlyGreetingStrategy.prototype = Object.create(GreetingStrategy.prototype);
    FriendlyGreetingStrategy.prototype.sayHi = function() {
        return "Hey, ";
    };
     
    var BoredGreetingStrategy = function() {};
    BoredGreetingStrategy.prototype = Object.create(GreetingStrategy.prototype);
    BoredGreetingStrategy.prototype.sayHi = function() {
        return "sup, ";
    };
     
    var politeGreeter = new Greeter(new PoliteGreetingStrategy());
    var friendlyGreeter = new Greeter(new FriendlyGreetingStrategy());
    var boredGreeter = new Greeter(new BoredGreetingStrategy());
     
    politeGreeter.greet(); //=> 'Welcome sir, Goodbye.'
    friendlyGreeter.greet(); //=> 'Hey, Goodbye.'
    boredGreeter.greet(); //=> 'sup, Goodbye.'
    </code>
    Определив метод execute, GreetingStrategy создаёт семейство алгоритмов. В приведенном выше фрагменте, мы воспользовались этим, создав несколько их разновидностей.

    Даже без использования подклассов, Greeter все еще обладает полиморфизмом. Нету необходимости переключаться на Greeter другого типа, чтобы вызывать нужный нам алгоритм. Теперь все они есть в каждом новом объекте Greeter.
    <code class="javascript">var greeters = [
        new Greeter(new BoredGreetingStrategy()),
        new Greeter(new PoliteGreetingStrategy()),
        new Greeter(new FriendlyGreetingStrategy()),
    ];
     
    greeters.forEach(function(greeter) {
        // Так как каждый `greeter` может использовать свою стратегию
        // нету никакой необходимости проверять его тип.
        // Мы просто запускаем его метод `greet`,
        // а он уже сам разберётся как его обработать.
        greeter.greet();
    });
    </code>

    СТРАТЕГИЯ в реальном кодеОдин из моих любимых примеров использования СТРАТЕГИИ — библиотека Passport.js.

    Passport.js предоставляет простой способ управления аутентификацией в node.js. Она поддерживает большое число провайдеров (Facebook, Twitter, Google и др.), каждый из которых представлен в виде отдельной стратегии.

    Библиотека доступна в виде npm-пакета, так же как и все её стратегии. Программист волен решать, какой npm-пакет устанавливать в данном конкретном случае. Вот фрагмент кода, который наглядно показывает, как это работает:
    <code class="javascript">// взято от сюда http://passportjs.org
    
    var passport = require('passport')
        // Каждый метод аутентификации представлен отдельным npm-пакетом.
        // Они дополняют Контекст новыми стратегиями.
      , LocalStrategy = require('passport-local').Strategy
      , FacebookStrategy = require('passport-facebook').Strategy;
    
    // Passport может быть объявлен через любую стратегию.
    passport.use(new LocalStrategy(
      function(username, password, done) {
        User.findOne({ username: username }, function (err, user) {
          if (err) { return done(err); }
          if (!user) {
            return done(null, false, { message: 'Incorrect username.' });
          }
          if (!user.validPassword(password)) {
            return done(null, false, { message: 'Incorrect password.' });
          }
          return done(null, user);
        });
      }
    ));
    
    // Здесь, мы используем стратегию Facebook
    passport.use(new FacebookStrategy({
        clientID: FACEBOOK_APP_ID,
        clientSecret: FACEBOOK_APP_SECRET,
        callbackURL: "http://www.example.com/auth/facebook/callback"
      },
      function(accessToken, refreshToken, profile, done) {
        User.findOrCreate(..., function(err, user) {
          if (err) { return done(err); }
          done(null, user);
        });
      }
    ));
    </code>
    Библиотека Passport.js сама по себе содержит только пару простых механизмов аутентификации. В ней нет ничего, кроме них и Контекста. Эта архитектура позволяет сторонним программистам легко реализовывать свои собственные механизмы аутентификации, не загромождая проект.

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

    Так или иначе, использование СТРАТЕГИИ, в первую очередь, позволяет масштабировать код, избегая больших накладных расходов на архитектуру. Это видно на примере Passport.js, в котором, использование этого паттерна, способствуют безболезненному добавлению новых стратегий от других программистов.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    НАСА готовит эксперимент для проверки концепции варп-двигателя

    Знатокам научно-фантастических произведений (в частности, сериала Star Trek) хорошо известно, что основным двигателем на кораблях Звёздного флота Федерации планет является именно варп-двигатель. В научно-фантастических произведениях исключительно подробно объясняют принцип его работы.



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

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

    Однако, инженер НАСА Гарольд Уайт (Harold White) уверен, что есть способ значительно снизить затраты энергии. Он убедил руководство НАСА провести эксперимент по созданию пузырей Алькубьерре в лабораторных условиях для проверки теории, пишет New Scientist.

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


    Иллюстрация из презентации Гарольда Уайта для конференции “100 Year Starship Symposium” в Орландо (2011)

    Корабль с варп-двигателем может выглядеть примерно так.



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

    Идею впервые предложили в 1994 году, и тогда расчёт показал, что нужно слишком большое количество энергии. На долгое время практическую реализацию варп-двигателя пришлось отложить. Но в 2011-2012 гг Гарольд Уайт сделал собственные расчёты — и нашёл способ снизить требования к энергозатратам на много порядков, так что теоретически можно создать варп-поле для корабля диаметром 10 метров с разгоном до скорости в 10х от скорости света, говорит он.

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

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Горизонт планирования

    Часто мы делаем проекты продолжительностью в несколько месяцев. При этом горизонт планирования команд в Сибириксе — порядка пяти недель. В переложении на спринты — 3-5 спринтов (зависит от опыта конкретной команды).

    Я использую два монитора, Google-календарь, Scrumban, общую тетрадь и песочные часы. Сам способ постоянно дорабатывается, но общие принципы остаются неизменными: держать под рукой все проекты в рукописном виде + управлять движением проектов на виртуальной канбан-доске.



    Сама процедура занимает 2 часа в неделю. Этого времени достаточно, чтобы распланировать нагрузку примерно на 35-50 человек. Удобно делать либо рано утром в понедельник, либо в пятницу, во второй половине дня, либо в воскресенье вечером.

    Шаг 1. Концентрация на планировании. Разлиновка
    Планирование — одна из самых муторных задач, которые я не могу делегировать. Я ее ненавижу. Вдобавок, я достаточно ленив, и всегда пытаюсь отложить планирование на самый последний момент. Однако я знаю, что взамен получу ясность и контроль над ситуацией. Это подстегивает начать. Примерно в воскресенье, часов в 6 вечера.

    Хотя вся информация по проектам есть в электронном виде — я намеренно переписываю ее на бумагу. Это дает полную картину по загрузке команд и позволяет восстановить чувство контроля — обычно оно покидает меня полностью за две недели (если я пропустил планерку) или за одну командировку.



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

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



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

    Если попадаются праздничные дни — штрихую.



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


    Разлиновка занимает примерно 20 минут и позволяет мне сконцентрироваться на задаче.

    Шаг 2. Планирование того, что гарантированно случится
    Следующее, что я делаю — запускаю Google Calendar и последовательно открываю рабочие календари команд. В календаре проставлены плановые спринты и проекты, на которые уже зарезервированы люди (это текущие проекты, по которым уже идет ).



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

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

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

    Если прямо сейчас я не могу запланировать ресурсы, например, не знаю на 100% статус проекта или не уверен, какая команда подойдет лучше — я переношу его в специальный календарь «Новые проекты».



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

    Эта операция примерно на 40 минут.

    Шаг 4. Обработка сделок из CRM
    Далее я открываю сделки из CRM и прохожусь по ним последовательно. Часть из них — передана проджект-менеджерам (я записываю такие сделки в первом столбце, возле фамилии проджект-менеджера). Но большая часть из них назначена на аккаунтов. Эти потенциальные сделки я заношу в соответствующий список возле фамилии аккаунта.

    Разбор заявок из CRM занимает порядка 10 минут.

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



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

    Руководствуясь опытом и интуицией, в пустые места я добавляю проекты из календаря «Новые проекты». Например, карандашом. Удаляю проект из календаря «Новые проекты» и ставлю задачу на конкретную команду.

    Это занимает еще минут 20, если нет жесткой нехватки ресурсов.



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

    Шаг 6. Внутренние задачи
    Если остаются какие-либо «дырки» в календарях команд — самое время поставить туда внутренние задачи компании либо запланировать обучение.

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

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    NASA разрабатывает лазерную систему связи со спутниками/роверами

    image

    В настоящее время NASA находится в стадии реализации весьма интересного проекта, цель которого — создание «широкого» (само собой, быстрого) канала связи для передачи данных с космических аппаратов/марсоходов/луноходов на Землю и обратно. Если все пройдет хорошо, то ученые Земли смогут получать качественные снимки космоса и других планет, HD видео и стереоскопические «картинки» наиболее интересных объектов.

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

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

    Отношение download/upload в данном случае составит 622/20mbps.

    Вот и видео от NASA, посвященное данному проекту:


    Via theverge

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Метрика #20 — Подкаст о технологиях и проектировании интерфейсов и сервисов

    Всем привет! С вами «Метрика» — шоу для тех, кто создает и анализирует продукты и , проектирует и руководит, занимается бизнесом и любит новые технологии.

    Сегодня в программе

    В 20-м выпуске Метрики вас ждет интервью Платона с Кириллом Рожковским, ИТ-предпринимателем, наиболее известным по таким проектам как WapStart и OmyConf.

    Предыдущие выпуски Метрики можно найти в нашем блоге по тегу «Подкаст».

    Заметки

    Твиттер Платона
    Твиттер Димы
    Facebook Кирилла
    LinkedIn Кирилла
    WapStart — сайт компании
    Текущий проект Кирилла — OmyConf

    Подробнее о проекте OmyConf и истории Интернет-предпринимательства Кирилла можно почитать на: Unova, ToWave и Коммерсанте.

    Парочка видео-интервью: раз и два.

    Метрика в iTunes Store
    RSS

    Слушать подкаст
    Скачать подкаст


    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    PDB-файлы доступны для загрузки в подписках DXperience и Universal

    Уже много лет компоненты DevExpress в подписках верхнего уровня поставляются вместе с полным исходным кодом. Это очень удобно и для клиентов, которые могут воспользоваться им как справочником в вопросах, не затронутых документацией, и для тех.поддержки, которая может написать «смотрите исходный код» в случае необходимости. Более того, имеются скрипты для самостоятельной сборки компонентов. Кому-то это будет полезно для доработки компонентов под свои задачи. Но уверен, что большинство как и я использовало пересборку для получения отладочной информации. И до недавнего времени это был единственный (из бесплатных) способ ходить по коду DevExpress в отладке.

    Я не буду перечислять здесь все неудобства, которые он в себе таит. Но в качестве аналогии приведу историю из личного опыта.
    Недавно я приобрел духовой шкаф. И в нем не хватило одной решетки в комплектации. В магазине в качестве единственного решения проблемы предложили увезти некомплектную духовку и привезти комплектную. Как разработчик я не мог пойти на такую вопиющую неоптимальность! Благо прямой звонок производителю позволил решить вопрос — мне просто привезли недостающую решетку.
    И вот, свершилось! Теперь в DevExpress тоже можно заказать решетку отдельно во всех подписках с исходным кодом (на данный момент это DXperience и Universal) доступна возможность загрузить полный набор PDB-файлов! А в базе знаний появилась статья, посвященная их применению.

    Приятной отладки!

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Из песочницы] За кулисами EuroSTAR. Или взгляд на организацию конференции со стороны председателя программного комитета Майкла Болтона

    От авторов перевода

    В преддверии конференции SQA Days 14 (которая в этом году пройдет в культурной столице Украины, в городе Львове) хотелось бы поделиться информацией которая призвана помочь потенциальным докладчикам сделать превосходные доклады, улучшить качество и облегчить работу программных комитетов многих конференций. В этой статье Майкл Болтон делится опытом и взглядом со стороны программного комитета самой передовой конференции в области тестирования и обеспечения качества — EuroSTAR на процесс приема и оценки докладов. Эта статья будет также полезна тем кто видит себя в будущем докладчиком и стремится выступать на конференциях. В процессе перевода мы старались сделать тест максимально понятным и адаптированным к актуальным условиям выступлений на конференциях которые проходят на просторе СНГ. Желаю вам приятного изучения данной статьи и удачи на выступлениях.

    Вступление

    Когда почти 300 человек соревнуются менее чем за 60 мест и за возможность выступить на такой конференции как EuroSTAR, не удивительно, что многие подавшие доклады, могут быть разочарованы отказом. С тех пор, как программа EuroSTAR 2013 была анонсирована, некоторые потенциальные докладчики просили обратную связь относительно своих заявок на выступление. И тем, кто обратился, я обязательно предоставляю эту информацию в индивидуальном порядке. Но, в начале хотелось бы дать несколько рекомендаций по подаче успешных докладов, основанных на моем опыте как председателя программного комитета в этом году.
    Будь то доклад на конференции, семинар, либо мастер-класс (назовем это выступлением) — все это является информационным продуктом. Предложение такого продукта — это , что-то вроде технического описания, которое помогает убедить потенциального покупателя в ценности программы. Хороший рекламный материал завоевывает и удерживает внимание потенциального слушателя, в данном случае — внимание программного комитета. Ваша заявка покажется лучше, если она описывает уникальное и убедительное выступление, определяет его пользу и не включает негативных факторов, которые могут повлиять на его ценность.



    Будьте лаконичны в описании

    Фактически не существует конференций, где количество и величина заявок на выступление было бы недостатком и вы, наверное понимаете, что рецензенты будут заняты. В процессе приема докладов на конференцию EuroSTAR 2013, программный комитет вычитал около 420 предложений, каждое в среднем по 300 слов. Что составило 126 000 слов, а это эквивалентно книге от 400 до 500 страниц. Одна из заявок состояла из 2044 слов в длину и напоминала 5-страничную статью из журнала. В результате заявка не была принята. Поэтому, будьте кратки и редактируйте описание докладов таким образом, что бы каждое слово было весомым.

    Придерживайтесь определенных правил при подаче доклада

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

    Все новое — хорошо забытое старое

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

    Сосредоточьтесь на решениях больше, чем на проблеме

    Тезисы докладов этого года в большинстве случаев начинались определением проблем в тестировании. И я, без сомнений, отдавал предпочтение тем докладам, которые показывали разные варианты решений или оптимизацию процессов основанные на реальном опыте. Для сравнения, некоторые тезисы содержали несколько сотен слов, описывая жалобы на проблему, потом следовало одно или два предложения вроде: «На этом докладе я расскажу что-то такое, (не уточняется) что сделает всем хорошо”.
    Выделить одну-две проблемы, которые вы планируете раскрыть на докладе это не плохо, но они не должны доминировать в тезисах. Сосредоточьтесь на теме вашего выступления, на том что будет полезно услышать, не зависайте на проблемах, переходите к решениям быстро.
    Я часто ловил себя на том, что оставляю такой комментарий: “Эта тема была бы хороша для блога”. Тем не менее, люди идут на конференции не для того, чтобы слушать кого-то, кто декларирует посты из блога.
    Убедитесь, что ваша презентация направлена на ту аудиторию, которая соберется в зале. Например, я принимал участие во многих конференциях по тестированию, где во время выступлений тестировщики критиковали то, что у них нет лучших менеджеров. Если вы хотите осветить проблему плохого менеджмента, предложите идеи относительно того, как тестировщики могут помочь улучшить ситуацию, доносите решения до менеджеров, или подавайте свои тезисы на конференцию по менеджменту.
    Делайте правильные выводы
    Некоторые из участников оплачивают свое участие в конференции самостоятельно, остальные участвуют за счет компании. Особенно во втором случае, люди, ответственные за финансирование, захотят увидеть, каким образом тестировщик, и организация в целом, сможет получить пользу от посещения конференции. Как конференция поможет участникам стать лучшими в своей области, толковыми и умелыми специалистами? Бесспорно, мы никогда не можем знать, сколько участников действительно чему-то научатся, мы этого не контролируем, но вы можете преподнести информацию таким образом и составить презентацию так, что бы участникам было очевидно какие знания и выводы они смогут вынести с доклада.

    Опишите, что вы ожидаете от аудитории

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

    Примите во внимание, что рецензент может быть не знаком с вами лично

    Так же как и отчеты о тестировании, вполне ожидаемо, что вашу заявку на выступление читают люди, которые никогда вас не видели. На EuroSTAR 2013 программный комитет видит информацию о заявке, но по традиции тезисы делаются анонимными для рецензентов. Таким образом, для последнего играет роль больше то, что есть в описании, нежели ваша репутация.
    Сделайте название вашего доклада ясным, наглядным и эффектным, хорошо структурируйте содержание учитывая вышеуказанные пункты.
    Используйте активный залог, формулируйте предложения от первого лица («На этом докладе я расскажу вам про Х», а не «На этом докладе будет рассказано про Х», «Мы отработаем с вами навык Y», вместо «Данные упражнения на умение Y»)
    Если в ваших тезисах будут орфографические или грамматические ошибки, рецензент может решить, что ваша презентация и другие материалы также могут содержать ошибки, особенно, если он не знает, кто вы.
    Избегайте профанации. Одно дело привлечь внимание, но будьте осторожны с тем, какой тип внимания вы привлекаете. Как говорится в рекламе одного американского шампуня: “… у вас никогда не будет второго шанса, что бы заново произвести первое впечатление”.
    Будьте осторожны с метафорами
    Во время наших совещаний, член Программного комитета Алан Ричардсон дал такой совет: если вы предлагаете метафору X, как первичную метафору для вашего доклада, удостоверьтесь, что вы имели в виду именно эту метафору Х. Или как минимум, сообщите рецензенту, какие были проведены исследования по теме Х, или каким образом вы дошли до понимания этой метафоры Х.

    Продумайте название вашего доклада

    Хороший рецензент постоянно обдумывает как будет выглядеть название презентации в буклете конференции? Даю наводку: попробуйте сначала написать текст аннотации. Найдите копию программы прошлогодней конференции – лучше всего, если это будет печатная версия, если такова недоступна, вы можете попробовать найти ее в сети либо на сайте конференции. Просмотрите образцы названий выступлений и их описания. Какие вам кажутся интересными, а какие нет? Почему они привлекли ваше внимание или оттолкнули вас? Какие стилистические нотки задержали ваше внимание? Определите среднюю величину (для EuroSTAR это около 150 слов) и формат описания. Как вы опишете свое выступление, используя такой формат? Попробуйте написать образец вашего личного описания доклада, сравните его с форматом описанным выше.
    Затем можете подать заявку, используя описание как основной блок. Расширьте этот рекламный текст таким образом, чтобы “продать” ваше выступление комитету. Напишите основу, области которые вы планируете рассмотреть; укажите структуру выступления, план доклада; опишите упражнения. Не пытайтесь игнорировать рецензентов отсутствием деталей и туманными обещаниями, неожиданный поворот сюжета здесь не поможет, а лишь может привести к неудаче.
    Не стоит считать, что написанная вами аннотация будет окончательным вариантом. Если ваша заявка будет принята, вы сможете пересмотреть этот текст и возможно вас даже попросят это сделать, чтобы предлагаемый материал лучше вписался в программу конференции.

    Если чего-то не знаете, спросите сразу

    Если что-то вам кажется непонятным в процессе приема доклада или вы не уверены, что ваша заявка соответствует теме и структуре конференции. Спросите у кого-то из программного комитета. Некоторые программные комитеты не станут рассматривать такие запросы. Однако не следует считать, что они так поступают всегда. В этом году комитет EuroSTAR оказывал помощь и поддержку в подготовке докладчиков к выступлению.

    Протестируйте ваше предложение

    Руководство к подаче докладов (на пример: sqadays.com/article.sdf/sqadays/sqa_days14/for_speakers) на которое мы ссылаемся в процессе приема заявок (адаптировано редактором), содержит определенные советы по подготовке убедительного выступления. Поскольку заявка на доклад является вашим продуктом, считайте это руководство инструментом для тестирования вашего предложения. Подобно всем документам в тестировании он не является исчерпывающим, но содержит ценные идеи. Для лучшего результата обратитесь к другим лицам с просьбой критически оценить ваш доклад.

    Волков бояться в лес не ходить

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

    Душу вложишь — все сможешь

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

    Майкл Болтон выражает благодарность Барту Брокману, Рикарду Эдґрену, Маарет Пайхеджарви и Алану Ричардсону за их вклад и редактирование этой статьи.
    Благодарность Кристине Ромашко и Рине Ужевко за их вклад в работу по переводу, вычитке и редактированию статьи.
    Источник: www.eurostarconferences.com/blog/2013/5/1/a-view-from-the-chair-with-michael-bolton-%28volume-4%29-%281%29


    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Custom layout. Выплывающая панель + параллаксный скроллинг

    Привет, коллеги.

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



    Расширяем существующий компонент

    Для простоты реализации я решил не расширять с нуля ViewGroup, а наследоваться от FrameLayout. Это избавит от необходимости реализации базовых рутинных вещей, таких, как измерение детей, компоновка и т. п., но в то же время предоставит достаточно гибкости для реализации нашей затеи.
    Итак, создаем класс DraggablePanelLayout.
    Первое, что мы хотим сделать, — модифицировать процедуру компоновки, чтобы верхний слой был смещен вниз, и лишь его часть выглядывала. Для этого переопределим onLayout:
    <code class="java">@Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    	super.onLayout(changed, left, top, right, bottom);
    
    	if (getChildCount() != 2) {
    	    throw new IllegalStateException("DraggedPanelLayout must have 2 children!");
    	}
    
    	bottomPanel = getChildAt(0);
    	bottomPanel.layout(left, top, right, bottom - bottomPanelPeekHeight);
    
    	slidingPanel = getChildAt(1);
    	if (!opened) {
    	    int panelMeasuredHeight = slidingPanel.getMeasuredHeight();
    	    slidingPanel.layout(left, bottom - bottomPanelPeekHeight, right, bottom - bottomPanelPeekHeight
    		    + panelMeasuredHeight);
    	}
    }
    </code>

    Здесь все просто: мы ограничиваем наш layout так, чтобы он мог хранить лишь двух потомков. Затем принудительно смещаем верхнего потомка вниз и сжимаем снизу нижнего. Давайте сделаем простейший layout и посмотрим, что у нас получилось:

    <code class="xml"><com.dataart.animtest.DraggedPanelLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:dp="http://schemas.android.com/apk/res/com.dataart.animtest"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        dp:bottom_panel_height="64dp"
        tools:context=".MainActivity" >
    
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/stripes" >
    
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:contentDescription="@string/android"
                android:src="@drawable/android" />
        </FrameLayout>
    
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#FFFFFF"
            android:text="@string/hello_world" >
    
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:text="@string/random_button" />
        </FrameLayout>
    
    </com.dataart.animtest.DraggedPanelLayout>
    </code>



    Как видим, нижняя панель успешно сместилась вниз. То, что нам нужно.

    Добавляем перетягивание пальцем

    Для реализации перетягивания панельки пальцем нужно переопределить метод onTouchEvent. Здесь мы при нажатии пальцем (ACTION_DOWN) запомним, в каком месте пользователь нажал, далее при движении пальцем (ACTION_MOVE), мы будем смещать наши панели, и, наконец, при ACTION_UP, мы завершим действие. Завершение действия, пожалуй, самая интересная задача, но об этом дальше.

    <code class="java">@Override
    public boolean onTouchEvent(MotionEvent event) {
    	if (event.getAction() == MotionEvent.ACTION_DOWN) {
    	    startDragging(event);
    	} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
    	    if (touching) {
    		float translation = event.getY() - touchY;
    		translation = boundTranslation(translation);
    		slidingPanel.setTranslationY(translation);
    		bottomPanel
    			.setTranslationY((float) (opened ? -(getMeasuredHeight() - bottomPanelPeekHeight - translation)
    				* parallaxFactor : translation * parallaxFactor));
    	    }
    	} else if (event.getAction() == MotionEvent.ACTION_UP) {
    	    isBeingDragged = false;
    	    touching = false;
    	}
    	return true;
     }
    </code>

    Здесь все просто. Метод boundTranslation ограничивает перемещение панели пальцем в рамках экрана, setTranslation задает смещение.

    Здесь мне хочется сделать небольшое отступление и поговорить о layout и translation. Layout — это процесс компоновки вашей разметки, т. е. для каждого View рекурсивно определяется его размер и положение на экране. Как не трудно догадаться, это затратная операция. Именно поэтому очень не рекомендуется выполнять эту процедуру при анимации, если вы только не хотите получить эффект тормозящей анимации. Свойство translation, в свою очередь, позволяет задать дешевое смещение элемента относительно заданной позиции без выполнения компоновки всей иерархии. Это очень полезно при анимациях. Помимо translation, у View есть такие свойства, как Rotation, Scale. Более продвинутые преобразования также возможно делать, создав подкласс желаемого компонента и выполняя необходимые преобразования канвы. Пример этого можно увидеть в моей предыдущей статье про анимирование ListView.

    Еще раз, но кратко и капсом. Главное правило при анимациях —НЕ ВЫПОЛНЯТЬ LAYOUT!!!

    Завершение жеста

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

    <code class="java">public void finishAnimateToFinalPosition(float velocityY) {
    	final boolean flinging = Math.abs(velocityY) > 0.5;
    
    	boolean opening;
    	float distY;
    	long duration;
    
    	if (flinging) {
    	    opening = velocityY < 0;
    	    distY = calculateDistance(opening);
    	    duration = Math.abs(Math.round(distY / velocityY));
    	    animatePanel(opening, distY, duration);
    	} else {
    	    boolean halfway = Math.abs(slidingPanel.getTranslationY()) >= (getMeasuredHeight() - bottomPanelPeekHeight) / 2;
    	    opening = opened ? !halfway : halfway;
    	    distY = calculateDistance(opening);
    	    duration = Math.round(300 * (double) Math.abs((double) slidingPanel.getTranslationY())
    		    / (double) (getMeasuredHeight() - bottomPanelPeekHeight));
    	}
    
    	animatePanel(opening, distY, duration);
    }
    </code>

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

    <code class="java">public void animatePanel(final boolean opening, float distY, long duration) {
    	ObjectAnimator slidingPanelAnimator = ObjectAnimator.ofFloat(slidingPanel, View.TRANSLATION_Y,
    		slidingPanel.getTranslationY(), slidingPanel.getTranslationY() + distY);
    	ObjectAnimator bottomPanelAnimator = ObjectAnimator.ofFloat(bottomPanel, View.TRANSLATION_Y,
    		bottomPanel.getTranslationY(), bottomPanel.getTranslationY() + (float) (distY * parallaxFactor));
    
    	AnimatorSet set = new AnimatorSet();
    	set.playTogether(slidingPanelAnimator, bottomPanelAnimator);
    	set.setDuration(duration);
    	set.setInterpolator(sDecelerator);
    	set.addListener(new MyAnimListener(opening));
    	set.start();
    }
    </code>

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

    <code class="java">@Override
    public void onAnimationEnd(Animator animation) {
    	    setOpenedState(opening);
    
    	    bottomPanel.setTranslationY(0);
    	    slidingPanel.setTranslationY(0);
    
    	    requestLayout();
    }
    </code>

    Перехват touch’a у других элементов

    Сейчас, если мы поместим, например, кнопку на нашу панельку, увидим, что, если попытаться тянуть панель, нажав пальцем на кнопку, мы не сможем этого сделать. Кнопка нажмется, но наша панель останется неподвижной. Это потому, что кнопка
    «крадет» у панели событие touch и обрабатывает его сама.
    Стандартный подход — перехватывать событие, убедиться, что мы действительно тянем панель, а не просто клацнули по кнопке, и отобрать контроль у кнопки, полностью захватив его нашим компонентом. Специально для этого у View есть метод onInterceptTouchEvent. Логика работы этого метода и взаимодействия с onTouchEvent весьма нетривиальна, но хорошо расписана в документации.

    <code class="java">@Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
    	if (event.getAction() == MotionEvent.ACTION_DOWN) {
    	    touchY = event.getY();
    	} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
    	    if (Math.abs(touchY - event.getY()) > touchSlop) {
    		isBeingDragged = true;
    		startDragging(event);
    	    }
    	} else if (event.getAction() == MotionEvent.ACTION_UP) {
    	    isBeingDragged = false;
    	}	
    
    	return isBeingDragged;
    }
    </code>

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

    Завершение

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

    Все исходники компонента доступны на github. Помимо того, что описано в статье, реализация добавляет:
    1. рисование тени между панелями;
    2. кастомные аттрибуты;
    3. использование hardware layers для ускорения анимации.
    Спасибо за внимание.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Офис мечты: какой он?

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

    На рабочем месте в офисе многие из нас проводят около трети своей жизни — 8-9 часов в день. Отдельные «счастливчики» дотягивают до 10-12 часов. И очень немногие из специалистов могут, не покривив душой, назвать своё рабочее место идеальным. Конечно, требования людей к рабочему месту определяются не только личными вкусами, но и особенностями профессии. И сегодня мы хотели бы затронуть тему идеального рабочего места с точки зрения IT-специалистов.

    В конце июля Mail.Ru Group и HeadHunter провели небольшое исследование. Мы опросили 691 IT-специалиста и выяснили, что для них важнее всего в офисном пространстве.




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

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

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

    Увы, реалии мало кому позволяют соблюдать это правило в жизни. Кроме того, мозг устроен таким образом, что для него важна не только продолжительность, но и количество сеансов сна в сутки. Именно с этим связана дневная сонливость, приходящаяся на 13–15 часов. Учёными давно подтверждена необходимость перерыва на дневной сон, который позволяет восстановить работоспособность и бодрость. Даже просто перерыв в тихой комнате с приглушённым светом, где можно расслабиться, закрыть глаза и отвлечься от офисной суеты, звонков, планов и коллег, может помочь восстановить силы, очистить голову и поднять настроение.

    Это подтверждают и опрошенные нами специалисты, 52% из которых хотели бы иметь в своём офисе рекреационную зону с диванчиком или даже кроватью, где можно вздремнуть, а 33% были бы рады массажному креслу.



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

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

    Кстати, Стив Джобс в офисе студии Pixar сделал целый бар со сладостями — Pixar's Cereal Bar (в котором более 100 наименований разных вкусняшек), про который даже сняли небольшой фильм.

    Эмоции
    Влияние эмоционального состояния человека на его рабочую деятельность преуменьшается как многими работодателями, так и самими сотрудниками. Ещё одной особенностью работы нашего мозга является падение его производительности во время эмоциональных всплесков. Причём «знак» эмоции не имеет значения. Однако в целом длительность таких всплесков невелика, поэтому куда большее значение имеют такая угнетающая мышление человека эмоция, как страх. Увы, современная жизнь далека от размеренности, и всевозможные страхи так или иначе проникают в жизнь каждого человека: мы боимся за свое здоровье и здоровье близких людей, боимся остаться без средств к существованию, боимся начальства, роста цен, гопников во дворе, темноты и миллионов других вещей. Бороться со страхами и отрицательными эмоциями, не только мешающими работать, но и отравляющими нашу жизнь в целом, можно самыми разными путями. В применении к IT-офису это различные способы релаксации и генерации положительных эмоций. Например, 44% наших респондентов пожелали бы иметь в офисе душевую, 27% отдали предпочтение компьютерным и настольным играм.

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

    Помимо получения информации о предпочтениях IT-специалистов мы решили также узнать, насколько их текущие рабочие места соответствуют «офису мечты». Увы, на сегодняшний день таким полным набором могут похвастаться лишь 8% IT-специалистов. Остальные в большинстве своем (63%) утверждают, что, возможно, рабочее место оснащено и не по последнему слову техники, но в принципе все необходимое у них есть. Существенный дискомфорт испытывают 28% опрошенных, которые утверждают, что рабочее пространство организовано неэффективно: у одних отсутствует необходимый второй монитор, у других программное обеспечение выдает ошибки из-за использования компанией нелицензионных программ, а кто-то жалуется на маломощный компьютер, возможностей которого для эффективной работы явно недостаточно. Лишь 7% опрошенных нами сообщили, что компания организует для них бесплатное питание в столовой или кафе, а также перекусы в виде фруктов, бутербродов, напитков или сладкого на кухне.

    Кому-то представленные выше пожелания могут показаться необоснованными. Однако большая часть сказанного будет верной для подавляющего большинства офисных работников. И мы не можем сказать, что IT-специалисты отличаются прихотливостью. Несмотря на внушительный список пожеланий, 37% айтишников уверяют, что им не нужен навороченный офис — их вполне устроил бы обычный, зато комфортный и уютный. Тем не менее, 27% не отказались бы от высокотехнологичного офисного пространства, 24% — от офиса в стиле дзен, а 10% видят идеальным местом для работы собственную квартиру или дом.



    Опрос проводился Службой исследований HeadHunter 15–30 июля 2013 г. среди 691 IT-специалиста.

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

    Надеемся, что этот пост позволит вам сделать «ревизию» вашего рабочего места и, кто знает, может быть причиной того, что вы не уложились в дедлайн, является банальное отсутствие душевой? :)


    Что вы хотели бы видеть в своём «офисе мечты»?


    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста. Проголосовало 1300 человек. Воздержалось 160 человек. Источник: habrahabr.ru,
    получено с помощью rss-farm.ru




    Бассейн



    Душевую



    Кухню с бесплатной едой



    Массажное кресло



    Компьютерные, настольные игры и др. развлечения



    Мини-детсад, няню



    Рекреационную зону



    Спортивный зал



    Другое

    Тестирование 10 Гбит / с серверов в Нидерландах, теперь серверы доступны и в US! От $2999 / месяц!

    В этой статье я расскажу о принципе подбора правильной конфигурации для мультигигабитного стримминг-решения, но для начала немного рекламы :). Более месяца назад мы анонсировали новость о начале предоставления выделенных серверов в Нидерландах с гарантированным каналом 10 Гбит / с без ограничения трафика.

    http://ua-hosting.com.ua/nl-servers.html — заказ 10 Гбит / с серверов доступен здесь.

    Пришла пора сообщить, что это правда и реальность и в данный момент лучшее предложение на рынке, помимо этого мы первые начинаем предоставлять подобные серверы в США и, кроме того, еще больше понижаем акционные цены. Теперь у Вас есть возможность арендовать сервер с выделенным 10 Гбит / с подключением в сеть Интернет без ограничения трафика по цене от $2999 / месяц, в зависимости от выбранной конфигурации, в локациях Нидерланды или США на выбор! Регламентируемый срок установки серверов 7-14 рабочих дней после оплаты, однако в реальности мы зачастую выдаем серверы уже через день после их заказа.

    Тут лишними будут какие-либо слова, загрузки канала одного из клиентов говорит сам за себя:

    image

    image

    Да, некоторым нашим клиентам и 10 Гбит / с мало :)

    Но крайне важно подобрать правильную конфигурацию под Ваш проект, чтоб выделенный 10 Гбит / с канал мог использоваться в полной мере и максимально эффективно. Так, сервер в начальной конфигурации Intel Xeon E3-1230 / 8GB DDR3 / 2x500GB SATA2 / 10Gbps Unmetered зачастую не способен отдать даже 1 Гбит / с трафика, не то, что 10.

    image

    Причина — ограничение IOPS-дисков (операции чтения / записи в секунду), которое определяется типом диска и его конструкцией и о котором нужно помнить всегда. Конечно, если все Ваши файлы смогут уместится в оперативной памяти сервера в кеше — это ограничение не проблема, но зачастую оперативной памяти будет мало.

    Если Вы не уверены, не знаете своей нагрузки (сколько пользователей будут скачивать / смотреть файлы одновременно) — запрашивайте замену SATA-дисков на SSD и ставьте побольше оперативной памяти, разница в цене в несколько сот долларов несущественна в сравнении с общей стоимостью аренды 10 Гбит / с решения, не экономьте. Не существует ничего более эффективного, чем SSD.

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

    7,200 об/мин SATA-диски ~75-100 IOPS (варьируется в зависимости от того блоками какого размера считываются данные, последовательно или случайно, производится ли запись и т.п.)
    15,000 об/мин SAS-диски — ~175-210 IOPS

    Intel X25-M G2 MLC SSD ~8 600 IOPS
    OCZ Vertex 3 SSD ~60 000 IOPS (Произвольная запись 4K)
    OCZ Vertex 3 MAX IOPS SSD ~75 000 IOPS (Произвольная запись 4K)
    OCZ Vertex 4 SSD ~120 000 IOPS (Произвольная запись 4K)
    OCZ RevoDrive 3 X2 SSD ~200 000 IOPS (Произвольная запись 4K)
    OCZ Z-Drive R4 CloudServ SSD ~500 000 IOPS PCIe

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

    Но так как 10 Гбит / с серверы зачастую используют именно для отдачи файлов, стримминга видео, то SSD вне конкуренции. Тем более, что SSD в отличии от SATA «умирают» прогнозировано, время жизни определяется количеством операций перезаписи, которые при помощи контроллера более-менее равномерно распределяются по диску, а после «смерти» диска восстановить данные с него возможно. Таким образом, если идет в основном считывание Ваших файлов, SSD, в отличии от SATA, может жить практически «вечно». Хотя бекапы все равно делать нужно.

    Для примера приведем результат генерации трафика при помощи такой конфигурации 2 x Intel Hexa-Core Xeon E5-2420 / 96GB DDR3 / 8x240GB SSD / 10Gbps Unmetered:

    image

    Проблема в том, что SSD на порядок дороже SATA и зачастую требуется пользователям разместить порой до 10 ТБ данных на одном сервере и более, физически сложно организовать хранилище такого объема данных в одном сервере на SSD и смысла мало. Распределение файлов на несколько серверов — также не всегда экономически выгодно.

    В таких случаях приходится комбинировать SATA и SSD диски, используя последние, как кеш для часто запрашиваемых файлов. Но подобные варианты уже требуют специфических знаний в администрировании и настройке «кластера» с балансером нагрузки. Как показал опыт, объем SSD под кеш должен составлять не менее 10% от объема файлов на SATA, так же полезной может быть репликация файов на разные SATA-диски и, как следствие, отдача одного и того же файла разным посетителям с разных дисков. Использование RAID-массивов в данных случаях, как аппаратных, так и программных — не эффективно. Уже при трафике свыше 4 Гбит / с могут возникать проблемы в виде падения скорости отдачи определенных файлов некоторым пользователям. По этой причине диски нужно использовать раздельно.

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

    Неплохим вариантом для таких целей может быть 2 x Intel Octa-Core Xeon E5-2650 / 128GB RAM / 8x3Tb + 4xSSD 240 Gb / IPMI/ 10Gbps Unmetered (в случае, если стоит задача конвертировать видео) либо 2 x Intel Hexa-Core Xeon E5-2420 / 96GB DDR3 / 6x3TB SATA2 + 6x240GB SSD / IPMI / 10Gbps Unmetered в случае стримминга, но без конвертации, когда процессор не критичен. Несколько красивых графиков с вышеуказанных реальных серверов клиентов:

    image

    image

    image

    image

    image

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

    Если Ваше видео имеет битрейт 1,5 Мбит / с и есть задача в его просмотре онлайн 5000 человек одновременно — Вам необходим минимальный канал 7500 Мбит / с + хотя бы 10-15% сверху для буферизации, либо предусмотреть возможность понижения качества транслируемого потока. Ну и не нужно забывать о том, что посещаемость Ваших сайтов все время меняется, все зависит от выдачи поисковых систем, лучше иметь, как минимум 30% канала в резерве.

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

    image

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [recovery mode] Решение транспортной задачи при помощи генетического алгоритма как часть SOA

    Решение транспортной задачи при помощи генетического алгоритма как часть SOA

    Приветствую уважаемое Хабрасообщество!

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

    Формулировка задачи


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

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


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

    Генетический алгоритм


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

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

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

    Все маршруты явно начинаются со склада и неявно им заканчиваются.

    Скрещивания
    Имеем 2 типа скрещиваний – случайный (Random Crossover) и однородный (Uniform Crossover)
    Случайное скрещивание – произвольная часть произвольного маршрута от родителя 1 помещается в наилучшее место вставки для родителя 2. Наилучшее место вставки – то которое дает наименьшую длину.
    image
    Однородное скрещивание вычисляет индексы плотности для всех маршрутов родителей и поочередно добавляет маршруты с наименьшим индексом от родителей 1 и 2. Оставшиеся точки распределяются в места наилучшей вставки.

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

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

    Фитнесс функция
    Приспособленность (качество) каждой хромосомы считается по формуле:
    Фитнесс = общее расстояние + штраф за перегруз * перегруз + штраф за недогруз * недогруз

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

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

    Результаты работы алгоритма
    Ниже приведены результаты работы алгоритма на подмножестве стандартного набора задач. Первая цифра в названии проблемы – число точек, вторая – мин количество машин. B-n31-k5 – 31 точка при 5 машинах.
    Результаты работы на 8 ядерном AMD (8350):
    image

    Результаты работы на всех тестовых данных находятся на странице проекта.

    Архитектура решения


    Решение написано на C# и состоит из ряда сервисов, баз данных и очередей:
    image
    Стек технологий:
    1. .NET 4.5 / C# / WCF / WinService
    2. Queue: RabbitMQ
    3. DB: MongoDB
    4. DI container: Autofac
    5. Unit tests: MS Test / Rhino Mocks / Fluent assertions

    .NET специфичный опыт которым я считаю нужным поделится:
    1. В часто обращаемых участках кода не используйте свойств, а просто публичные переменные
    2. Массивы зачастую быстрее списков (List) и словарей (Dictionary) даже при реализации в них операций вставки внутрь и удаления элементов

    Следующие шаги


    Текущее решение доступно бесплатно.
    Список новой функциональности которая находится в разработке:
    1. Получение расстояний по координатам точек
    2. Добавление ограничений – по временным окнам, машинам и точкам доставки

    Список литературы


    Гугл содержит массу публикаций о решении задачи средствами генетических (и не только) алгоритмов. Вот названия некоторых из них:
    1. Solving the Vehicle Routing Problem with Genetic Algorithms
    2. A hybrid algorithm for the Vehicle Routing Problem with Time Windows
    3. A Route-directed Hybrid Genetic Approach for the Vehicle Routing Problem with Time Windows

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    А давайте действительно заблокируем правительству доступы к сайтам?

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

    image
    Давайте же отлучим наших интернетов!


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

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

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Дайджест инициатив РОИ

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

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

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

    Закон о криптовалюте (биткоинах)

    Автор инициативы предлагает законодательно признать криптовалюту (биткоины) на территории РФ.
    — Прямо прописать криптовалюты в закон о «Национальной платёжной системе»;
    — Создать необходимые для функционирования банкоматов и обменников документы;
    — Дать банкам юридические возможности работать с криптовалютами;
    — Добавить в ОКВЭД код «генерация хешей криптовалюты»;
    — Предоставить валютным биржам механизмы для торгов по криптовалютам;
    — Разрешить физическим и юрлицам принимать платежи в биткоинах.

    Введение равного тарифа страховых взносов для всех организаций, осуществляющих деятельность в области информационных технологий, устранение дискриминации малых ИТ компаний (численностью до 30 человек)

    Автор инициативы предлагает уравнять размер стразовых взносов для всех ИТ компаний, вне зависимости от количества сотрудников
    В настоящее время для организаций, осуществляющих деятельность в области информационных технологий, сильно различаются ставки страховых взносов. Для организаций с численностью сотрудников свыше 30 человек (Статья 58 ч.1. п.6 ФЗ №212-ФЗ, статья 57 ч.2.1 ), ставка составляет 14% (Статья 58, часть 3 ФЗ №212-ФЗ), причем она будет сохраняться до 2017 года. Для прочих организаций, осуществляющих деятельность в области информационных технологий, то есть с численностью сотрудников менее 30 человек, ставка составляет 20% (и то только при условии, что организация применяет упрощенную систему налогообложения), причем она действует последний год (Статья 58, 3.4 ФЗ №212-ФЗ).

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

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

    Технологии дистанционного присутствия в экономике, капитализация и перспективы развития России

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

    Оснащение светофоров радиомаяками на основе wifi-технологий для дистанционного информирования водителей транспортных средств о сигналах светофора

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

    Ввести президента РАН в Правительство РФ в статусе министра по науке и высоким технологиям

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

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

    Автор инициативы предлагает в школах (или других образовательных учреждениях) ввести обучение «слепой печати»
    Ввести в образовательных учреждениях, обучение печати на клавиатуре компьютера слепым десяти пальцевым методом повсеместно на законодательном уровне. Для обучения требуется 25-30 часов. Внедрив методику в образовательных учреждениях, учебные учреждения начнут выпускать профессионалов всех видов владеющих 10-пальцевым методом (юристы, врачи и пр.), это уже усовершенствованный специалист, который работает быстрее, XXI Век – век скоростей.

    Налог с каждого провайдера на финансирование авторов книг и музыки пропорционально количеству скачек их произведений в Единой Электронной Библиотеке

    Автор инициативы предлагает создать Российскую Единую Публичную Электронную Библиотеку и ввести дополнительный налог с интернет-провайдеров в пользу Российской Единой Публичной Электронной Библиотеки.
    Исходя из объема рынка услуг по доступу в интернет для частных лиц примерно в 60-70 млрд. руб., общий фонд РЕПЭБ составит около 6 млрд. Если 3 млрд. из них будет потрачено на гонорары собственно писателей, то тем самым около 3000 авторов в среднем получат 1 млн. руб. в год. Этого достаточно для сохранения профессиональной среды и формирования конкурентного сообщества.

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

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

    Право на доступ в Интернет

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

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

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

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

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

    Установка веб-камер в кабинетах чиновников с выводом изображения в интернет

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

    Дешёвый спутниковый интернет для труднодоступных населённых пунктов

    Автор инициативы предлагает за счёт государственных средств для труднодоступных населённых пунктов организовать дешёвый доступ в интернет (300-500 руб./мес.) через спутниковую связь.
    Россия — огромная страна, с большим количеством людей, проживающих в труднодоступных местах, которые не имеют доступа к высокоскоростному интернету. Предлагаю (на государственные деньги) создать и запустить геостационарный спутник, который покроет всю территорию России дешёвым, высокоскоростным интернетом.

    Защита интернет пространства России от иностранных агентов

    Автор инициативы предлагает создать реестр сайтов-иностранных агентов
    В России не прошел сценарий твиттерно-фейсбучной оранжевой революции, подход США изменился, отвечая вызову — и инвестиции также возрасли (сумма покупки е1 по слухам порядка миллиарда рублей!). Теперь аудитория проамериканских сайтов сравнима с аудиторией федеральных каналов. И идеологическая обработка приобретает совершенно другие, откровенно опасные для России масштабы.

    Единный расчетный счет и интернет-сервис для заключения договоров

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

    Обязать каждую Управляющую Компанию (УК), ТСЖ, каждую структуру ЖКХ иметь свой сайт в системе Интернет

    Автор инициативы предлагает обязать управляющие компании и ТСЖ создавать свои сайты.
    На сайте УК (ТСЖ) каждый собственник жилой площади, обслуживаемый этой УК или являющийся членом ТСЖ, должен иметь свой Личный кабинет, в котором он может посмотреть свой лицевой счет, проверить правильность начислений за предоставленные коммунальные услуги, указать показания квартирных счетчиков на воду, газ, свет, тепло, распечатать квитанцию на оплату услуг ЖКХ, оплатить услуги ЖКХ банковской картой прямо с сайта.

    Целесообразно открыть свободный доступ к диссертациям РГБ через Интернет

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

    Введение на ПОЧТЕ РОССИИ услуги «Интернет-открытка»

    Автор инициативы предлагает обязать Почту России ввести услугу «Интернет-открытка», оплачиваемую пользователем по банковской карте через интернет. Услуга позволила бы отправить через форму на сайте Почты России текст на выбранном бланке открытки.
    ПОЧТЕ РОССИИ не пришлось бы «возить» по две недели письма и думать ночами и днями напролёт КАК уменьшить время доставки. Так можно не только открытки посылать, но и письма. Не нужно марки печатать, специальные конверты, сортировать потом все это и рассылать каким-либо транспортом.

    Публикация информации об уголовных и административных правонарушениях в Интернете

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

    И ещё две интересные инициативы:

    Ленин и Мавзолей

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

    Запрет на продажу бутербродов без масла

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

    А теперь голосование:


    Нужен ли дайджест инициатив РОИ на Хабре?


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



    Нужен



    Не нужен


    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста. Проголосовало 182 человека. Воздержалось 26 человек. Где ещё вы хотели бы видеть дайджест инициатив?



    Все важные инициативы (по мнению автора)



    Инициативы, связанные с ИТ-отраслью (как в этой подборке)



    Инициативы, связанные с ИТ-отраслью и немножко важных инициатив по мнению автора


    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста. Проголосовало 92 человека. Воздержалось 98 человек. Источник: habrahabr.ru,
    получено с помощью rss-farm.ru




    В группах в соц. сетях (вконтакте, facebook)



    На отдельном ресурсе



    На других площадках аналогичных Хабру (развлекательных ресурсах, коллективных блогах и т.п.)

    О системе диалогов Deus Ex и реальных механиках в настольных играх

    Deus Ex Human Revolution — произведение искусства в лучших традициях киберпанка, своего рода IT-RPG. Игра отличная и стильная с крутым сюжетом и массой проработанных деталей. Но самое, на мой взгляд, крутое в ней – это система диалогов как механика.

    Сейчас объясню в чём дело. Посмотрите на вот эти два скриншота: первый из Fallout II, второй из нового Deus Ex.


    Старая добрая диалоговая система


    Диалог в Deus Ex с установленным в голову социальным модулем

    Классические диалоги и в Fallout II, и в Deus Ex очень похожи: вам достаточно выбирать варианты ответов. В обоих случаях, если вы хотите убедить собеседника, нужно продумать линию поведения. На кого-то можно надавить, перед кем-то извиниться, кому-то сказать напрямик и так далее.

    Интересное наступает в том случае, если вы получите социальный перк в Fallout или установите социальный модуль в Deus Ex. В первом случае диалоги не изменятся, но все ответы будут подсвечиваться цветами: синий – понравится оппоненту, красный разозлит его и так далее. Всё просто и никаких лишних знаний не надо.

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


    Социальный модуль определяет реакцию «альфа» по сердцебиению

    Что изменилось? Во-первых, вы видите, как собираются данные. Вы предварительно «калибруете» собеседника, разведывая по его микрореакциям тип характера и modus operandi. А затем принимаете решение о том, как лучше воздействовать – какой конкретно стратегией. При этом модуль создаёт новые диалоги (ветки, которых не было бы без него), но не меняет результаты – в большинстве случаев того же самого можно было добиться, просто выбирая правильные варианты обычным способом.

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

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

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

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

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

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

    И вот здесь уместно посмотреть на настолки

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

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

    Возвращаясь к системе диалогов. На мой взгляд, в Deus Ex есть кое-что волшебное и новое. По крайней мере, в зачаточном виде.

    P.S. Да, и игра – хорошая и очень атмосферная. Если не видели — советую. Только не убивайте себе рабочие дни.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Из песочницы] Старые ОС: IBM VM/370

    Здравствуйте, уважаемые хабарчане!
    Я интересуюсь «древними» компьютерами и операционными системами. Несмотря на их древность, многие из них гораздо более продуманнее современных систем и лучше подходят в качестве примеров. Windows и Linux есть чему поучиться у многих устаревших ОС.
    По-моему самые интересные из старых систем — мейнфреймы и поздние миникомпьютеры (супермини). В отличие от ранних миникомпьютеров, которые часто лепились на коленке конечного пользователя под его нужды, системы мейнфреймов и супермини с самого начала были предназначены для людей не имеющих ни полного представления о работе компьютера ни времени на разработку отдельной архитектуры для каждой задачи. При этом, в отличие от современных систем (4 гигабайта оперативки на набор этого поста), мейнфреймы и в особенности супермини были очень ограниченны в ресурсах и не как правило не разрастались.
    В этом посте я опишу процесс установки операционной системы VM/370. VM/370 — операционная система IBM для компьютеров IBM System/370. Это многопользовательская ОС работающая по принципу гипервизора control program (CP): каждому пользователю предоставляется своя виртуальная машина, в которой он может запустить желаемую ОС, в частности сам гипервизор CP (немногие современные гипервизоры способны на такой трюк) и CMS — однопользовательскую ОС, бабушку MS-DOS. Прямой потомок VM — zVM до сих пор используется на мейнфреймах IBM System z. Подробнее о VM можно прочитать в Википедии.
    Для тех кто хочет не красноглазить, а просто посмотреть конечный результат: есть готовые образы системы с подробными инструкциями (правда на английском). Остаток статьи можно не читать.


    Материалы и инструменты

    Для установки и работы нам понадобится:

    Подготовка.

    Все фалы проекта я помещаю в папку /home/link/Programming/LEGACY/SYSTEMS/System360/vm370habr (далее просто vm370habr). Загруженные образы сохраняем в папку vm370habr/DISTR. В vm370habr создаю подпапку IO.

    Создание образов дисков
    <code class="bash">link@link-K73BY ~/Programming/LEGACY/SYSTEMS/System360/vm370habr/DASD $ dasdinit -z VMREL6 3330-11 VMREL6
    HHCDU044I Creating 3330 volume VMREL6: 808 cyls, 19 trks/cyl, 13312 bytes/track
    HHCDU041I 808 cylinders successfully written to file VMREL6
    HHCDI001I DASD initialization successfully completed.
    link@link-K73BY ~/Programming/LEGACY/SYSTEMS/System360/vm370habr/DASD $ dasdinit -z CPR6L0 3330 CPR6L0
    HHCDU044I Creating 3330 volume CPR6L0: 404 cyls, 19 trks/cyl, 13312 bytes/track
    HHCDU041I 404 cylinders successfully written to file CPR6L0
    HHCDI001I DASD initialization successfully completed.
    link@link-K73BY ~/Programming/LEGACY/SYSTEMS/System360/vm370habr/DASD $ 
    
    </code>
    Диски в терминах System360 называются DASD. Программа dasdinit создает чистые образы дисков. Первый образ — диск модели 3330 с меткой VMREL6. На него мы запишем стартовую систему. Второй диск — CPR6L0, модели 3330-11 (в два раза большей емкости), на него установим гипервизор. Диски архивированы (опция -z), эту опцию лучше не применять на медленных компьютерах.

    Файл конфигурации для монитора
    Создаем в папке vm370habr текстовый файл hercules.cnf со следующим содержанием:
    <code class="bash">ARCHMODE	S/370   # Мы хотим эмулировать компьютер S/370, 
    CPUMODEL	3158    #  модели 3158.
    CPUSERIAL	000777  # Это поле не имеет значения.
    ECPSVM		NO      # Отключить ускорение виртуализации (пока я с ним не разобрался).
    MAXCPU		1       # Однопроцессорная система.
    NUMCPU		1       # С одним процессором включённым при старте (привет, кеп)
    OSTAILOR	VM      # Не оповещать нас о "странных" для многих ОС, но типичных для VM ошибках.
    
    LOADPARM  	0120....# Если честно, я сам не понял что это.
    
    MAINSIZE	16      # 16 мегабайт оперативной памяти (по тем временам - роскошь).
    XPNDSIZE	0       # Без дополнительной памяти (CP её не использует).
    
    # Адрес папки с нашей системой.
    DEFSYM MyDir /home/link/Programming/LEGACY/SYSTEMS/System360/vm370habr
    
    # Номер TCP/IP порта для telnet.
    CNSLPORT	3270
    
    ##################################################
    ##              Устройства                      ##
    ##################################################
    # В System/370 устройства адресуются (в простейшем случае)
    #  тремя шестнадцатеричными цифрами:
    # - Номером канала,
    # - Номером управляющего блока,
    # - Номером устройства. 
    # На управляющем блоке должны висеть устройства сходных типов.
    # На первый канал имеет смысл подключать медленные устройства.
    
    # Первый столбец - адрес устройства.
    # Второй - тип.
    # Дальше идут настройки, для всех устройств разные. Их точное значение
    # можно посмотреть в руководстве Геркулеса.
    
    008	3215-C NOPROMPT	# Первый телетайп для оператора системы.
    009     3215   NOPROMPT	# Второй телетайп для управления установкой. 
    
    00C	3505	# Ввод перфокарт.
    00D	3525	$(MyDir)/IO/punch ascii crlf    # Вывод перфокарт.
    00E	1403	$(MyDir)/IO/printer crlf        # Принтер.
    
    020-02F	3270	# Графические терминалы.
    
    ######## Диски
    130	3330	$(MyDir)/DASD/CPR6L0
    131	3330	$(MyDir)/DASD/VMREL6
    
    #######
    180-18F	3420	*       # Ленточные накопители.
    </code>

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

    Настройка дисков

    <code class="bash">link@link-K73BY ~/Programming/LEGACY/SYSTEMS/System360/vm370habr $ hercules
    #...много текста
    Command ==>devinit 180 DISTR/starter-3330.aws
    HHCTA004I 0180: DISTR/starter-3330.aws is a AWS Format tape file                                                                                             
    HHCPN098I Device 0:0180 initialized                                                                                                                          
    </code>
    В другом терминале:
    <code class="bash">link@link-K73BY ~/Programming/LEGACY/SYSTEMS/System360/vm370habr $ telnet localhost 3270
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    Hercules version 3.07 built on Jun 19 2011 04:29:21
    running on link-K73BY (Linux-3.0.0-26-generic.#43-Ubuntu SMP Tue Sep 25 17:19:22 UTC 2012 x86_64 MP=2)
    Connected to device 0:0009
    </code>
    В окне с Геркулесом:
    <code class="bash">Command ==>ipl 180                                                                                                       
    </code>
    (ipl, на мейнфреймовском жаргоне — то же самое что и boot).
    В окне с телнетом появится следующее:
    <code class="bash">VM/370 FORMAT/ALLOCATE PROGRAM RELEASE 6
    ENTER FORMAT OR ALLOCATE:                                                                               
    </code>

    Форматирование дисков
    В System/370 концепт данных на диске отличался от современного: размеры секторов мог быть различным даже на одной дорожке и часто определялись приложением, а не операционной системой. Подключенные к CP диски могут быть двух типов: резидентные диски CP (для системной информации и файлов подкачки) и диски пользователей, которые могут быть разбиты по цилиндрам на несколько минидисков. Оболочка CMS разбивает всё отведенное ей пространство диска на 800-байтные секторы и строит файловою систему по типу FAT.
    Насколько я понял, диск стартовой системы (CPR6L0) — это диск данных с особой сборкой ядра в первых цилиндрах. В качестве резидентного диска стартовая система (и новая установка ядра) будут использовать диск VMREL6. Для этого нам надо выделить на томе VMREL6 пространство для файлов подкачки и временных дисков. Я также отформатировал CPR6L0, потому что не уверен в том, что образы сгенерированные dasdinit подходят VM.
    На ленте с образом стартовой системы есть программа форматирования. В окне с телнетом:
    <code class="bash">ENTER FORMAT OR ALLOCATE:FORMAT
    FORMAT FUNCTION SELECTED
    ENTER DEVICE ADDRESS (CCU):131
    ENTER DEVICE TYPE:3330-11
    ENTER START CYLINDER (XXX) OR "LABEL":000
    ENTER END CYLINDER (XXX):807
    ENTER DEVICE LABEL:VMREL6
    FORMAT STARTED
    FORMAT DONE
    000 NO. PAGE RECORDS WITH READ-CHECK ERRORS
    ENTER FORMAT OR ALLOCATE:ALLOC
    ALLOCATE FUNCTION SELECTED
    ENTER DEVICE ADDRESS (CCU):131
    ENTER DEVICE TYPE:3330-11
    ENTER DEVICE LABEL:VMREL6
    ENTER ALLOCATION DATA FOR VOLUME VMREL6
    TYPE CYL CYL
    .... ... ...
    PERM 000 012
    DRCT 013 016
    TEMP 017 201
    PERM 202 202
    TEMP 203 389
    TDSK 390 402
    PERM 403 807
    END
    ALLOCATION RESULTS
    PERM 000 012
    DRCT 013 016
    TEMP 017 201
    PERM 202 202
    TEMP 203 389
    TDSK 390 402
    PERM 403 807
    DEVICE 131 VOLUME VMREL6 ALLOCATION ENDED
    ENTER FORMAT OR ALLOCATE:FORMAT
    FORMAT FUNCTION SELECTED
    ENTER DEVICE ADDRESS (CCU):130
    ENTER DEVICE TYPE:3330
    ENTER START CYLINDER (XXX) OR "LABEL":000
    ENTER END CYLINDER (XXX):403
    ENTER DEVICE LABEL:CPR6L0
    FORMAT STARTED
    FORMAT DONE
    000 NO. PAGE RECORDS WITH READ-CHECK ERRORS
    </code>

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

    Копирование стартовой системы
    В окне с геркулесом вводим:
    <code class="bash">stop                                                                            
    ipl 180                                                                         
    </code>
    В телнете появляется:
    <code class="bash">VM/370 DASD DUMP/RESTORE PROGRAM RELEASE 6
    ENTER CARD READER ADDRESS OR CONTROL STATEMENTS
    ENTER: 
    </code>
    Вводим:
    <code class="bash">ENTER CARD READER ADDRESS OR CONTROL STATEMENTS
    ENTER: SYSPRINT 00E
    ENTER: INPUT 180 3420
    ENTER: OUTPUT 130 3330 CPR6L0
    ENTER: RESTORE ALL
    RESTORING CPR6L0
    </code>
    Подождите несколько минут и Геркулес начинает выдавать сообщения об ошибках. Дело в том, что в программе DDR есть ошибка, которая не влияла на поведение на реальном железе, но вешает эмуляторы.
    Выйдите из Геркулеса командой quit и перезапустите Геркулес.

    Запуск и настройка стартовой системы

    Подключите к Геркулесу эмулятор дисплея (как это делать — см. мануал эмулятора). В Геркулесе наберите команду «ipl 130» и нажмите клавишу ввода в окне дисплея. На дисплее появится следующая картинка:В принципе, дисплей 3270 в исполнении CMS похож на обычную консоль. Единственное серьезное отличие — консоль не прокручивается автоматический, надо очищать экран кнопкой «Clear». Все остальное в принципе можно выяснить методом тыка.

    Настройка стартовой системы
    Сборка ядра стартовой системы отличается тем, что здесь адреса устройств не вшиты намертво в код, а задаются при каждом старте. Для моей конфигурации ответы такие:VM/370 STARTER SYSTEM RELEASE 6.0
    ENTER PRINTER ADDRESS (CUU):
    00e
    ENTER DEVICE TYPE (1403,1443,3211,3203,3800):
    1403
    ENTER PUNCH ADDRESS (CUU):
    00d
    ENTER DEVICE TYPE (2540P,3525):
    3525
    ENTER READER ADDRESS (CUU):
    00c
    ENTER DEVICE TYPE (2501,2540R,3505):
    3505
    ENTER ADDRESS WHERE PID TAPE IS MOUNTED (CUU):
    180
    ENTER DEVICE TYPE (2401,2415,2420,3420):
    3420
    ENTER ADDRESS WHERE SCRATCH TAPE IS MOUNTED (CUU):
    181
    ENTER DEVICE TYPE (2401,2415,2420,3420):
    3420
    ===Нажмите клавишу Clear===
    ENTER DEVICE ADDRESS WHERE SYSTEM RESIDENCE WILL BE BUILT (CUU):
    131
    ENTER DEVICE TYPE:
    3330
    ===Повторение настроек===
    ARE THE ABOVE SETTINGS CORRECT?
    YES
    ===Экран очищается===
    CHANGE TOD CLOCK (YES|NO):
    13:36:14 NO
    13:36:14 START ((COLD|WARM|CKPT|FORCE) (DRAIN))|(SHUTDOWN):
    13:36:21 COLD
    13:36:21 DMKLNK117E CPGEN 351 NOT LINKED; VOLID VMREL6 CONFLICT
    13:36:21 DMKLNK117E CPGEN 352 NOT LINKED; VOLID VMREL6 CONFLICT
    13:36:21 DMKLNK117E CPGEN 353 NOT LINKED; VOLID VMREL6 CONFLICT
    13:36:21 AUTO LOGON *** CPGEN USERS = 001 BY SYSTEM
    13:36:21
    DMKCPI952I 0512K SYSTEM STORAGE
    DMKCPI957I STOR 00512K, NUC 156K, DYN 00320K, TRA 008K, FREE 0028K, V=R 00000K
    13:36:21 FILES: NO RDR, NO PRT, NO PUN

    Теперь я настраиваю консоль:
    <code class="bash">spool console start
    terminal mode vm
    </code>
    Эти настройки нужны для того, чтобы при запуске CMS гипервизор передавал ей управление консолью. Но пока мы еще не запустили CMS, команды виртуальной машине уйдут в пустоту. Поэтому следите за надписью в правом нижнем углу экрана и вводить команды только по сигналу CP READ. Если в углу экрана надпись RUNNING, нужно нажать клавишу Enter, а если HOLDING — CLEAR.
    Определение установки
    Введите команду QUERY VIRTUAL DASD, чтобы проверить какие диски подключены. Результат должен быть таким:
    <code class="bash">13:52:55 DASD 190 3330 CPR6L0 R/O 085 CYL
    13:52:55 DASD 191 3330 CPR6L0 R/W 001 CYL
    13:52:55 DASD 194 3330 CPR6L0 R/W 027 CYL
    13:52:55 DASD 350 3330 VMREL6 R/W 808 CYL
    </code>
    Теперь нужно подключить том VMREL6 к виртуальной машине под тем же номером что и в реальной:
    define 350 as 131.

    Подключение лент
    Создайте в папке vm370habr пустой файл scratch.aws и введите в Геркулес следующие команды:
    <code class="bash">devinit 180 DISTR/ptf-616.aws
    devinit 180 scratch.aws
    </code>
    Первая лента — это патч системы, а вторая — пустая лента, на которую будет записано ядро.
    Теперь подключаем эти ленты к виртуальной машине. В окне дисплея:
    <code class="bash">attach 180 to cpgen as 181
    attach 181 to cpgen as 182
    </code>

    Загрузка CMS
    Введите в окно дисплея команду: «ipl 190 parm seg=null». Появится сообщение: «RELEASE 6 CMS 12/25/78». Нажмите клавишу ввода. Теперь вы работаете под управлением CMS и можете не беспокоиться о потере команд.
    Далее, создайте временный диск (он понадобиться для сборки ядра) командой «define t3330 192 11» и отформатируйте его командой format 192 d. (d — буква диска в CMS). Дальше все совсем как в DOSе. Метку можно назначить любую, я выбрал TMP192 (как в инструкции).
    Пару слов о файлах CMS: в CMS имя файла записывается так: через пробел восемь символов имени, восемь символов расширения, буква диска. То есть как в ранних DOS, но с точностью до наоборот.

    Применение патчей

    Отключите защиту от записи на системном диске CMS: «link cmssys 190 190 w write».
    Скопируйте содержимое диска a на диск d коммандой «copy * * a = = d» Символ «равно» в шаблонах CMS означает «без изменений».
    Скопируйте файлы патчей на диск d: «vmfplc2 load * * d». VMFPLC2 выведет такой список файлов:
    <code class="bash"> LOADING.....
     5749010  061638   D1
     VMSERV   EXEC     D1
     5749010  EXEC     D1
     VMFPLC2  MODULE   D2
     END-OF-FILE OR END-OF-TAPE
    </code>
    Теперь применим патчи:
    <code class="bash">access 192 c
    release a
    vmserv nomemo noipl
    </code>
    VMSERV выведет приветствие и начнет спрашивать какие патчи надо применить. Нам нужен сервис «5749010» и патч CP VM/370. «CP BASE STAGING AREA DISK ADDRESS» — 194. Также, ответьте «yes» на вопрос «IS THIS THE INITIAL SYSGEN OF THIS SYSTEM?».
    После этого, VMSERV применит патчи к CP и перезапустит CMS. Когда CMS выведет приветствие, подключите временный диск как диск a: «access 192 a».

    Подготовка к сборке ядра

    Введите «generate srvcpgm». Эта команда выведет перфокарты с сервисными программами (на эмуляторе они нам не понадобятся). Затем программа спросит печатать ли пример пользовательского каталога. Ответьте «yes» — в каталог может пригодиться. А карты с конфигурационными файлами не нужны — я приведу их ниже.

    Конфигурация ядра

    Ядро настраивается с помощью нескольких исходников на языке ассемблера и описания пользовательского каталога. Тем, кто хочет их настроить «по вкусу», придется долго копаться в мануалах, а я привожу готовый вариант:
    <code class="bash">ID CPGEN
    :READ MYVM DIRECT
    * CHANGE THE NEXT ENTRY FOR YOUR SYSTEM RESIDENCE DEVICE
    DIRECTORY 131 3330 VMREL6
    *
    USER OPERATOR OPERATOR 320K 1M ABCDEG
     ACCOUNT ACT1 OPERATOR
     CONSOLE 009 3215
     SPOOL 00C 2540 READER A
     SPOOL 00D 2540 PUNCH A
     SPOOL 00E 1403 A
     MDISK 191 3330 008 005 CPR6L0 WR READ WRITE
     LINK MAINT 194 194 RR
     LINK MAINT 190 190 RR
    *
    USER CE CE 320K 1M EFG
     ACCOUNT ACT2 CE
     CONSOLE 009 3215
     SPOOL 00C 2540 READER A
     SPOOL 00D 2540 PUNCH A
     SPOOL 00E 1403 A
     MDISK 191 3330 013 004 CPR6L0 WR READ WRITE
     LINK MAINT 194 194 RR
     LINK MAINT 190 190 RR
    *
    USER MAINT CPCMS 720K 16M BCEG
     ACCOUNT ACT3 MAINT
     OPTION ECMODE REALTIMER
     CONSOLE 009 3215
     SPOOL 00C 2540 READER A
     SPOOL 00D 2540 PUNCH A
     SPOOL 00E 1403 A
     MDISK 190 3330 030 085 CPR6L0 MR READ
     MDISK 191 3330 017 007 CPR6L0 WR READ
     MDISK 194 3330 115 027 CPR6L0 MR READ
     MDISK 199 3330 029 001 CPR6L0 WR READ
    *
     MDISK 300 3330 000 808 VMREL6 MW
    *
    *   THE ABOVE ENTRY SHOULD BE MODIFIED TO MATCH THE ADDRESS AND LABEL
    *   OF YOUR SYSTEM RESIDENCE VOLUME.  IT MAY THEN BE USED BY THIS ID
    *   TO LOAD A DIRECTORY AND WRITE A CP NUCLEUS.
    *   DELETE THE ' * ' (IN FRONT OF MDISK) ALSO.
    *   CHANGE THE '404' TO A '808' IF YOURS IS A 3330-11
    *
    *****
    USER IVPM1 IVPASS 320K 16M G
     ACCOUNT ACT4 IVPM1
     CONSOLE 009 3210
     SPOOL 00C 2540 READER A
     SPOOL 00D 2540 PUNCH A
     SPOOL 00E 1403 A
     MDISK 191 3330  001 001 CPR6L0 WR READ WRITE
     LINK MAINT 194 194 RR
     LINK MAINT 190 190 RR
    *
    USER IVPM2 IVPASS 320K 1M G
     ACCOUNT ACT5 IVPM2
     CONSOLE 009 3210
     SPOOL 00C 2540 READER A
     SPOOL 00D 2540 PUNCH A
     SPOOL 00E 1403 A
     MDISK 191 3330 002 001 CPR6L0 WR READ WRITE
     LINK MAINT 194 194 RR
     LINK MAINT 190 190 RR
    *
    USER RSCS RSCS 512K
     ACCOUNT ACT6 RSCS
     OPTION ECMODE
     CONSOLE 009 3215
     SPOOL 001 2540 READER A
     SPOOL 00C 2540 READER A
     SPOOL 00D 2540 PUNCH A
     SPOOL 00E 1403 A
     MDISK 191 3330 003 005 CPR6L0 WR READ WRITE
     LINK MAINT 190 190 RR
     DEDICATE 0B1 078
     DEDICATE 0B2 079
     DEDICATE 0B3 07A
    *
    USER ECMODE ECMODE 512K 1M G
     ACCOUNT ACT7 ECMODE
     OPTION ECMODE REALTIMER
     CONSOLE 009 3215
     SPOOL 00C 2540 READER A
     SPOOL 00D 2540 PUNCH A
     SPOOL 00E 1403 A
     MDISK 191 3330 024 005 CPR6L0 WR READ WRITE
     LINK MAINT 194 194 RR
     LINK MAINT 190 190 RR
    *
    USER OPERATNS OPERATNS 512K 1M BCEG
     ACCOUNT ACT8 OPERATNS
     CONSOLE 009 3215
     SPOOL 00C 2540 READER A
     SPOOL 00D 2540 PUNCH A
     SPOOL 00E 1403 A
     LINK MAINT 190 190 RR
    ****************
    *
    * THE FOLLOWING MINIDISK ENTRY IS PROVIDED AS AN EXAMPLE OF
    * THE SPACE RECOMMENDED FOR AN IPCS VIRTUAL MACHINE.
    * IF YOU INTEND TO USE THE OPERATNS USERID AS YOUR IPCS
    * VIRTUAL MACHINE, YOU SHOULD CHANGE THE FOLLOWING STATEMENT
    * TO ALLOCATE MINIDISK SPACE ON ONE OF YOUR SYSTEM DASD VOLUMES.
    *
    * MDISK 191 3330 XXX 015 YYYYYY WR READ WRITE
    *
    ****************
    *
    *
    *     CYLINDERS 142 TO 403 ARE UNUSED AND MAY BE USED FOR
    *     ANY OTHER VIRTUAL MINI DISK SPACE. IT CAN ALSO BE
    *     USED FOR PAGING, SPOOLING OR T-DSK SPACE.
    *
    *
    *
    
    :READ DMKRIO ASSEMBLE
    DMKRIO CSECT
    ******** Device definitions:
    * ****** Teletype
            RDEVICE ADDRESS=008,DEVTYPE=3215
    * ****** Card reader
            RDEVICE ADDRESS=00C,DEVTYPE=3505,CLASS=®
    * ****** Card punch
            RDEVICE ADDRESS=00D,DEVTYPE=3525,CLASS=(P)
    * ****** Printer
            RDEVICE ADDRESS=00E,DEVTYPE=1403,FEATURE=UNVCHSET,CLASS=(L)
    * ****** Terminals
            RDEVICE ADDRESS=(020,16),DEVTYPE=3277
    * ****** DASDs:
    *   **** System disks.
            RDEVICE ADDRESS=(130,2),DEVTYPE=3330,MODEL=11
    *   **** User disks.
            RDEVICE ADDRESS=(150,8),DEVTYPE=3330,MODEL=11
    * ****** Tapes.
             RDEVICE ADDRESS=(180,16),DEVTYPE=3420,MODEL=8,FEATURE=DUALDENS
    *
    ******** Control unit definitions:
    * ****** Printer (I don't know if this is requed):
            RCTLUNIT ADDRESS=000,CUTYPE=3811
    * ****** Slow IO:
            RCTLUNIT ADDRESS=008,CUTYPE=2821
    * ****** Terminals:
            RCTLUNIT ADDRESS=020,CUTYPE=3272,FEATURE=16-DEVICE
    * ****** System disks:
            RCTLUNIT ADDRESS=130,CUTYPE=3880,FEATURE=16-DEVICE
    * ****** User disks:
            RCTLUNIT ADDRESS=150,CUTYPE=3880,FEATURE=16-DEVICE
    * ****** Tapes:
            RCTLUNIT ADDRESS=180,CUTYPE=3803,FEATURE=16-DEVICE
    *
    ******** Channel definitions.
            RCHANNEL ADDRESS=0,CHTYPE=MULTIPLEXOR
            RCHANNEL ADDRESS=1,CHTYPE=BLKMPXR
    *
            RIOGEN CONS=008
            END
    :READ DMKSYS ASSEMBLE
    SYS      TITLE 'DMKSYS FOR 3330    RELEASE 6'                           00001000
    DMKSYS   CSECT                                                          00002000
             SYSOWN (VMREL6,TEMP)                                           00003000
             SYSRES SYSVOL=VMREL6,SYSRES=131,SYSTYPE=3330,                 X00004000
                   SYSNUC=7,SYSWRM=10,SYSERR=11,SYSCKP=202                  00005000
             SYSMON AUTO=NO                                                 00006000
             SYSJRL                                                         00007000
             SYSCOR RMSIZE=16M,AP=NO                                        00008000
             SYSOPR SYSOPER=OPERATOR,SYSDUMP=OPERATNS                       00009000
             SYSTIME ZONE=5,LOC=WEST,ID=EST                                 00010000
             SYSLOCS                                                        00011000
             END                                                            00012000
    :READ DMKSNT ASSEMBLE
    *.                                                                      00003000
    * MODULE NAME -                                                         00004000
    *        DMKSNT                                                         00005000
    *                                                                       00006000
    * FUNCTION -                                                            00007000
    *                                                                       00008000
    *        THIS MODULE WILL BE ASSEMBLED BY THE INSTALLATION SYSTEM       00009000
    *        PROGRAMMER. IT WILL DESCRIBE THE THE SYSTEM TO BE SAVED VIA    00010000
    *        THE 'SAVESYS' COMMAND AND TO BE IPL'ED BY NAME. SHARED SEG-    00011000
    *        MENTS MAY BE SPECIFIED. THESE SEGMENTS MUST CONSIST OF         00012000
    *        ALL REENTRANT CODE.                                            00013000
    *                                                                       00014000
    *                                                                       00015000
    *        INPUT TO THE NAMESYS MACRO IS SPECIFIED IN THE FOLLOWING       00016000
    *        FORMAT:                                                        00017000
    *                                                                       00018000
    *        LABEL NAMESYS    SYSSIZE=NNNK,SYSNAME=CCCCCC,VSYSRES=CCCCCC,   00019000
    *                         VSYSADR=XXX,SYSVOL=CCCCCC,SYSCYL=NNN,         00020000
    *                         SYSSTRT=(CC,P),SYSPGCT=NN,                    00021000
    *                         SYSPGNM=(NN,NN,NN-NN,......),                 00022000
    *                         SYSHRSG=(N,N,...)                             00023000
    *                                                                       00024000
    *        WHERE:                                                         00025000
    *                                                                       00026000
    *        SYSSIZE - THIS IS THE MINUMUM STORAGE SIZE NEEDED TO           00027000
    *                  OPERATE THE SAVED SYSTEM.                            00028000
    *        SYSNAME - IS THE NAME GIVEN THE SYSTEM TO BE USED FOR          00029000
    *                  IDENTIFICATION BY 'SAVESYS' AND 'IPL'.               00030000
    *        VSYSRES - IS THE VOLUME SERIAL OF THE DASD CONTAINING THE      00031000
    *                  SYSTEM TO BE SAVED                                   00032000
    *        VSYSADR - IS THE VIRTUAL ADDRESS OF THE DASD CONTAINING        00033000
    *                  THE SYSTEM.                                          00034000
    *        SYSCYL  - THE CYLINDER ADDRESS OF THE 'MINI-DISK'              00035000
    *                  FOR THE SYSTEM TO BE SAVED.                          00036000
    *        SYSVOL  - IS THE VOLUME SERIAL OF THE DASD DESIGNATED TO       00037000
    *                  RECEIVE THE SAVED SYSTEM. THIS MUST BE A             00038000
    *                 'CP-OWNED' VOLUME.                                    00039000
    *        SYSSTRT - THIS DESIGNATES THE STARTING CYLINDER AND PAGE       00040000
    *                  ADDRESS ON 'SYSVOL' THAT THIS NAMED SYSTEM IS TO     00041000
    *                  BE SAVED. DURING THE SAVESYS AND IPL PROCESSING,     00042000
    *                  THIS WILL BE USED TO MAKE UP THE 'CCPD' ADDRESS      00043000
    *                  FOR THE DASD OPERATIONS. THESE NUMBERS ARE TO        00044000
    *                  SPECIFIED IN DECIMAL.                                00045000
    *        SYSPGCT - IS THE TOTAL NUMBER OF PAGES TO BE SAVED.            00046000
    *        SYSPGNM - THESE ARE THE NUMBERS OF THE PAGES TO BE SAVED.      00047000
    *                  SPECIFICATION MAY BE DONE AS GROUPS OF PAGES OR      00048000
    *                  AS SINGLE PAGES. FOR EXAMPLE - IF PAGES 0,4, AND     00049000
    *                  10 THRU 13 ARE TO BE SAVED, USE THE FORMAT:          00050000
    *                  SYSPGNM=(0,4,10-13).                                 00051000
    *        SYSHRSG - THESE ARE THE SEGMENT NUMBERS DESIGNATED AS          00052000
    *                  SHARED. THE PAGES IN THESE SEGMENTS WILL BE SET      00053000
    *                  UP AT IPL TIME TO BE USED BE ANY USER                00054000
    *                  IPL'ING BY THIS NAME.                                00055000
    *                                                                       00056000
    *        THE FOLLOWING IS A SAMPLE OF INPUT FOR THIS MODULE:            00057000
    *                                                                       00058000
    *        DMKSNTBL CSECT                                                 00059000
    *        FSTNAME NAMESYS   SYSSIZE=256K,SYSNAME=CMS,VSYSRES=CPDSK1,     00060000
    *                          SYSVADR=190,SYSCYL=100,SYSVOL=CPDSK2,        00061000
    *                          SYSSTRT=(400,1),SYSPGCT=10,                  00062000
    *                          SYSPGNM=(0-5,10-13),SYSHRSG=(1,2)            00063000
    *                                                                       00064000
    * ATTRIBUTES -                                                          00065000
    *                                                                       00066000
    *        PAGEABLE                                                       00067000
    *                                                                       00068000
    * ENTRY POINTS -                                                        00069000
    *                                                                       00070000
    *        DMKSNTBL                                                       00071000
    *                                                                       00072000
    * NOTES -                                                               00073000
    *                                                                       00074000
    *        THERE IS NO EXECUTABLE CODE IN THIS MODULE.                    00075000
    *                                                                       00076000
    *                                                                       00077000
    *.                                                                      00078000
             EJECT                                                          00079000
    *                                                                       00080000
    *********************************************************************** 00081000
    *                                                                       00082000
    *        THE FOLLOWING ENTRIES ARE BASED ON THE INFORMATION INCLUDED    00083000
    *        IN THE SAMPLE DMKSYS PROVIDED WITH THE STARTER SYSTEM,         00084000
    *        AND THE SAMPLE ALLOCATIONS PROVIDED IN THE SYSTEM              00085000
    *        GENERATION PROCEDURE.                                          00086000
    *                                                                       00087000
    *********************************************************************** 00088000
    *                                                                       00089000
             SPACE                                                          00090000
    DMKSNTBL CSECT                                                          00091000
             SPACE                                                          00092000
    *                                                                       00093000
    *     THE SPACE FOR CMS IS ALLOCATED ON VMREL6, AS FOLLOWS:             00094000
    *          CYL 1, PAGE 01 TO CYL 1, PAGE 34  (34 PAGES)                 00095000
    *     TOTAL = 34 PAGES                                                  00096000
    *                                                                       00097000
    CMS      NAMESYS    SYSSIZE=256K,SYSNAME=CMS,                          X00098000
                   VSYSADR=190,SYSVOL=VMREL6,SYSCYL=030,SYSSTRT=(001,1),   X00099000
                   SYSPGCT=33,SYSPGNM=(0-32),SYSHRSG=(1),VSYSRES=CPR6L0     00100000
             EJECT                                                          00101000
    *                                                                       00102000
    *     THE SPACE FOR CMSSEG IS ALLOCATED ON VMREL6, AS FOLLOWS:          00103000
    *          CYL 1, PAGE 35 TO CYL 1, PAGE 51  (17 PAGES)                 00104000
    *     TOTAL = 17 PAGES                                                  00105000
    *                                                                       00106000
    CMSSEG   NAMESYS SYSNAME=CMSSEG,SYSVOL=VMREL6,SYSCYL=,                 X00107000
                   SYSSTRT=(001,35),SYSPGCT=16,SYSHRSG=(16),               X00108000
                   SYSPGNM=(256-271),SYSSIZE=64K,VSYSRES=,VSYSADR=IGNORE    00109000
             EJECT                                                          00110000
    *                                                                       00111000
    *     THE SPACE FOR CMSVSAM IS ALLOCATED ON VMREL6, AS FOLLOWS:         00112000
    *          CYL 1, PAGE 52 TO CYL 1, PAGE 57 ( 6 PAGES)                  00113000
    *          CYL 2, PAGE 01 TO CYL 2, PAGE 57 (57 PAGES)                  00114000
    *          CYL 3, PAGE 01 TO CYL 3, PAGE 34 (34 PAGES)                  00115000
    *     TOTAL = 97 PAGES                                                  00116000
    *                                                                       00117000
    CMSVSAM  NAMESYS SYSNAME=CMSVSAM,SYSVOL=VMREL6,SYSPGNM=(272-367),      X00118000
                   SYSSTRT=(001,52),SYSPGCT=96,SYSSIZE=384K,SYSCYL=,       X00119000
                   SYSHRSG=(17,18,19,20,21),VSYSRES=,VSYSADR=IGNORE         00120000
             EJECT                                                          00121000
    *                                                                       00122000
    *     THE SPACE FOR CMSAMS IS ALLOCATED ON VMREL6, AS FOLLOWS:          00123000
    *          CYL 3, PAGE 35 TO CYL 3, PAGE 57 (23 PAGES)                  00124000
    *          CYL 4, PAGE 01 TO CYL 4, PAGE 57 (57 PAGES)                  00125000
    *          CYL 5, PAGE 01 TO CYL 5, PAGE 49 (49 PAGES)                  00126000
    *     TOTAL = 129 PAGES                                                 00127000
    *                                                                       00128000
    CMSAMS  NAMESYS SYSNAME=CMSAMS,SYSVOL=VMREL6,SYSPGNM=(368-495),        X00129000
                   SYSSTRT=(003,35),SYSPGCT=128,SYSSIZE=448K,SYSCYL=,      X00130000
                   SYSHRSG=(23,24,25,26,27,28),VSYSRES=,VSYSADR=IGNORE      00131000
             EJECT                                                          00132000
    *                                                                       00133000
    *     THE SPACE FOR CMSDOS IS ALLOCATED ON VMREL6, AS FOLLOWS:          00134000
    *          CYL 5, PAGE 50 TO CYL 5, PAGE 57 ( 8 PAGES)                  00135000
    *          CYL 6, PAGE 01 TO CYL 6, PAGE 01 ( 1 PAGE )                  00136000
    *     TOTAL = 9 PAGES                                                   00137000
    *                                                                       00138000
    CMSDOS   NAMESYS SYSNAME=CMSDOS,SYSVOL=VMREL6,SYSHRSG=(31),            X00139000
                   SYSSTRT=(005,050),SYSPGCT=8,SYSSIZE=32K,SYSCYL=,        X00140000
                   SYSPGNM=(496-503),VSYSRES=,VSYSADR=IGNORE                00141000
             EJECT                                                          00142000
    *                                                                       00143000
    *     THE SPACE FOR INSTVSAM IS ALLOCATED ON VMREL6, AS FOLLOWS:        00144000
    *          CYL 6, PAGE  02 TO CYL 6, PAGE 10  ( 9 PAGES)                00145000
    *     TOTAL = 9 PAGES                                                   00146000
    *                                                                       00147000
    INSTVSAM   NAMESYS SYSNAME=INSTVSAM,SYSVOL=VMREL6,SYSHRSG=(254),       X00148000
                   SYSSTRT=(006,002),SYSPGCT=8,SYSSIZE=32K,SYSCYL=,        X00149000
                   SYSPGNM=(4064-4071),VSYSRES=,VSYSADR=IGNORE              00150000
    *                                                                       00151000
             EJECT                                                          00152000
    *                                                                       00153000
    *     THE SPACE FOR 3800 PRINTER IMAGES ON VMREL6 IS ALLOCATED:         00154000
    *          CYL 6, PAGE 11 TO CYL 6, PAGE 16  ( 6 PAGES)                 00155000
    *     TOTAL = 6 PAGES                                                   00156000
    *                                                                       00157000
             NAME3800 CPNAME=IMAG3800,SYSVOL=CPR6L0,SYSSTRT=(006,11),      X00158000
                   SYSPGCT=5                                                00159000
             EJECT                                                          00160000
    *                                                                       00161000
    *     THE FOLLOWING SPACE IS AVAILABLE FOR SAVED SYSTEMS ON VMREL6:     00162000
    *          CYL 6, PAGE 17 TO CYL 6, PAGE 57  (41 PAGES)                 00163000
    *     TOTAL = 47 PAGES                                                  00164000
    *                                                                       00165000
             END                                                            00166000
    </code>

    Копируем весь этот текст в файл sysconf.txt.

    Сборка ядра

    Вводим в консоли Геркулеса: «devinit 00c sysconf.txt ascii eof».
    И на дисплее: «generate vm370»
    GENERATE спросит имя файла с каталогом (у меня это MYVM DIRECT). Затем откомпилируются файлы с настройками и GENERATE спросит собирамемся ли мы использовать многопроцессорную систему или опцию V=R. Отвечаем no. Дальше будет много текста и (если вам повезет) в конце появится надпись: «NUCLEUS LOADED ON VMREL6».
    Сохраните карту памяти ядра и выключите стартовую систему:
    <code class="bash">close ptr
    15:06:30 IPL 190 PARM SEG=NULL
    15:06:30 PRT FILE 0019  TO  CPGEN    COPY 01 NOHOLD
    RELEASE 6 CMS 12/25/78
    access 194 a
    CMSSEG SYSTEM NAME 'NULL    ' NOT AVAILABLE.
    R; T=0.01/0.01 15:06:36
    read cpipcs map a
    RECORD LENGTH IS '132' BYTES.
    R; T=0.25/1.24 15:06:50
    drain all
    15:08:18 RDR  00C DRAINED   SYSTEM
    15:08:18 PUN  00D DRAINED   SYSTEM   CLASS = A      SEP
    15:08:18 PRT  00E DRAINED   SYSTEM   CLASS = A      SEP
    R; T=0.01/0.02 15:08:18
    shutdown
     
     
    DMKCKP960I SYSTEM WARM START DATA SAVED
     
    DMKCKP961W SYSTEM SHUTDOWN COMPLETE
     
    </code>

    Разбиение диска

    Для того, чтобы использовать диск CPR6L0, его нужно переразметить. Загрузите FORMAT/ALLOCATE так же, как при копировании системы.
    <code class="bash">VM/370 FORMAT/ALLOCATE PROGRAM RELEASE 6
    ENTER FORMAT OR ALLOCATE:ALLOCATE
    ALLOCATE FUNCTION SELECTED
    ENTER DEVICE ADDRESS (CCU):130
    ENTER DEVICE TYPE:3330
    ENTER DEVICE LABEL:CPR6L0
    ENTER ALLOCATION DATA FOR VOLUME CPR6L0
    TYPE CYL CYL
    .... ... ...
    DRCT 000 000
    PERM 001 403
    END   
    ALLOCATION RESULTS
    DRCT 000 000
    PERM 001 403
    DEVICE 130 VOLUME CPR6L0 ALLOCATION ENDED
    </code>
    Остановите программу командой stop.

    Запуск новой системы

    Загрузитесь с системного диска командой IPL 131. В окне Геркулеса появится приглашение:
    <code class="bash">NOW 14:14:40 EST MONDAY 08/26/13                                                                                                                             
    CHANGE TOD CLOCK (YES NO) 
    </code>
    Сейчас вы работаете в встроенной консоли. С точки зрения VM/CMS это такая же консоль, как и подключение через телнет. Для того, чтобы ввести текст во встроенную консоль, введите его в консоль Геркулеса через косую черту ("/"):
    <code class="bash">CHANGE TOD CLOCK (YES NO) :                                                                                                                                  
    /(0008) no                                                                                                                                                   
    14:17:49 START ((COLD WARM CKPT FORCE) (DRAIN)) (SHUTDOWN) :                                                                                                 
    /(0008) cold                                                                                                                                                 
    14:17:51 AUTO LOGON   ***   OPERATOR USERS = 001  BY  SYSTEM                                                                                                 
    DMKCPI957I STOR 16384K, NUC 224K, DYN 14900K, TRA 240K, FREE 1020K, V=R 00000K                                                                               
    14:17:51 FILES:  NO RDR,  NO PRT,  NO PUN                                                                                                                    
    14:17:51 FORMATTING ERROR RECORDING AREA                                                                                                                     
    </code>

    Форматирование минидисков
    Тут все просто:
    <code class="bash"> /(0008) ipl 190 parm seg=null                                                                                                                               
    14:22:39                                                                                                                                                     
    RELEASE 6 CMS 12/25/78                                                                                                                                      V
    /(0008) access (nodisk                                                                                                                                       
    CMSSEG SYSTEM NAME 'NULL    ' NOT AVAILABLE.                                                                                                                 
    DISK 'A' NOT ACCESSED.                                                                                                                                       
    DISK 'A' NOT ACCESSED.                                                                                                                                       
    R; T=0.01/0.01 14:22:49                                                                                                                                      
                                                                                                                                                                 
    /(0008) format 191 a                                                                                                                                         
    DMSFOR603R FORMAT WILL ERASE ALL FILES ON DISK 'A(191)'. DO YOU WISH TO CONTINUE? (YES NO):                                                                  
    /(0008) yes                                                                                                                                                  
    DMSFOR605R ENTER DISK LABEL:                                                                                                                                 
    /(0008) OPR191                                                                                                                                               
    FORMATTING DISK 'A'.                                                                                                                                         
    HHCCP048I 0130:CCW=07F06608 40100006=>00000FFF 00000000 00000000 000F8918 ..............i.                                                                   
    HHCCP075I 0130:Stat=0E00 Count=0000                                                                                                                          
    HHCCP076I 0130:Sense=80000000 380C1204 00000000 00000000 00000000 00000000                                                                                   
    HHCCP077I 0130:Sense=CMDREJ                                                                                                                                  
    '5' CYLINDERS FORMATTED ON 'A(191)'.                                                                                                                         
    R; T=0.01/0.11 14:23:13                                                                                                                                      
                                                                                                                                                                 
    /(0008) logoff                                                                                                                                               
    14:23:34 CONNECT= 00:05:42 VIRTCPU= 000:00.06 TOTCPU= 000:00.39                                                                                              
    14:23:34 LOGOFF AT 14:23:34 EST MONDAY 08/26/13                                                                                                              
                                                                                                                                                                 
                                                                                                                                                                 
                                                                                                                                                                 
     VM/370 ONLINE                                                                                                                                               
     /(0008) logon maint                                                                                                                                         
                                                                                                                                                                 
    ENTER PASSWORD:                                                                                                                                              
    XXXXXXXX                                                                                                                                                     
    /(0008) cpcms                                                                                                                                                
    LOGON AT 14:23:45 EST MONDAY 08/26/13                                                                                                                        
    /(0008) define storage 2m                                                                                                                                    
    STORAGE = 02048K                                                                                                                                             
    /(0008) ipl 190 parm seg=null                                                                                                                                
    RELEASE 6 CMS 12/25/78                                                                                                                                       
    /(0008) access (nodisk                                                                                                                                       
    CMSSEG SYSTEM NAME 'NULL    ' NOT AVAILABLE.                                                                                                                 
    DISK 'A' NOT ACCESSED.                                                                                                                                       
    DISK 'A' NOT ACCESSED.                                                                                                                                       
    R; T=0.01/0.01 14:25:26                                                                                                                                      
                                                                                                                                                                 
    /(0008) format 191 a                                                                                                                                         
    DMSFOR603R FORMAT WILL ERASE ALL FILES ON DISK 'A(191)'. DO YOU WISH TO CONTINUE? (YES NO):                                                                  
    /(0008) yes                                                                                                                                                  
    DMSFOR605R ENTER DISK LABEL:                                                                                                                                 
    /(0008) MNT191                                                                                                                                               
    FORMATTING DISK 'A'.                                                                                                                                         
    HHCCP048I 0130:CCW=07F07BB0 40100006=>00000FFF 00000000 00FFF280 000F6F38 ..........2...?.                                                                   
    HHCCP075I 0130:Stat=0E00 Count=0000                                                                                                                          
    HHCCP076I 0130:Sense=80000000 38171204 00000000 00000000 00000000 00000000                                                                                   
    HHCCP077I 0130:Sense=CMDREJ                                                                                                                                  
    '7' CYLINDERS FORMATTED ON 'A(191)'.                                                                                                                         
    R; T=0.02/0.26 14:26:30                                                                                                                                      
                                                                                                                                                                 
    /(0008) logout                                                                                                                                               
    CONNECT= 00:02:49 VIRTCPU= 000:00.07 TOTCPU= 000:00.52                                                                                                       
    LOGOFF AT 14:26:35 EST MONDAY 08/26/13                                                                                                                       
                                                                                                                                                                 
                                                                                                                                                                 
                                                                                                                                                                 
     VM/370 ONLINE                                                                                     
    
    /(0008) logon operator                                                                                                                                       
    ENTER PASSWORD:                                                                                                                                              
    XXXXXXXX                                                                                                                                                     
    /(0008) operator                                                                                                                                             
    14:28:10 LOGON AT 14:28:10 EST MONDAY 08/26/13                                                                                                               
    14:28:10 LINE 008 LOGON  AS OPERATOR USERS = 002                                                                               
    /enable all
    ===Много сообщений о неподключенных устройствах===                                                                                       
    </code>

    Установка обновлений
    Залогинтесь под пользователем MAINT через дисплей:
    <code class="bash">LOGON MAINT
    ENTER PASSWORD:
     
    DASD 190 LINKED R/W; R/O BY OPERATOR
    DASD 194 LINKED R/W; R/O BY OPERATOR
    LOGON AT 14:30:29 EST MONDAY 08/26/13
     
    CP
    IPL 190 PARM SEG=NULL
    RELEASE 6 CMS 12/25/78
     
    CMSSEG SYSTEM NAME 'NULL    ' NOT AVAILABLE.
    R; T=0.01/0.01 14:30:54
    </code>
    Пароль — CPCMS.
    Подключите ленту с обновлениями к машине MAINT (через консоль Геркулеса):
    <code class="cs">devinit 180 ./DISTR/ptf-616.aws                                                                                                                              
    HHCTA101I 0180: AWS Tape ./DISTR/starter-3330.aws closed                                                                                                     
    HHCTA004I 0180: ./DISTR/ptf-616.aws is a AWS Format tape file                                                                                                
    HHCPN098I Device 0:0180 initialized                                                                                                                          
    /(0008) attach 180 to maint as 181                                                                                                                           
    14:32:43                                                                                                                                                     
    14:32:43 TAPE 180 ATTACH TO MAINT    181                                                                                                                     
    
    </code>

    Теперь в консоли администратора:
    <code class="bash">vmfplc2 rew
    R; T=0.01/0.01 14:33:26vmfplc2 load
     LOADING.....
     5749010  061638   A1
     VMSERV   EXEC     A1
     5749010  EXEC     A1
     VMFPLC2  MODULE   A2
     END-OF-FILE OR END-OF-TAPE
    R; T=0.02/0.10 14:33:33
    access 191 c
    '191 A ' RELEASED
    R; T=0.01/0.01 14:34:16
    vmserv restart 5749010 cp nomemo
    </code>
    Дальше будет много вопросов. Лично я отвечаю наугад — в результате, как и следовало ожидать, ошибка. Но это не критично.

    Сохраняем CMS

    В CP есть механизм, похожий на динамические библиотеки — Named Systems. Одно из частых его использований — ускорение работы с CMS. Для того чтобы сохранить CMS как именованную систему, нужно выполнить следующие команды:
    <code class="bash">define storage 2m
    STORAGE = 02048K
    CP ENTERED; DISABLED WAIT PSW '00020000 00000000'
    IPL 190 PARM SEG=NULL
    RELEASE 6 CMS 12/25/78
     CMSSEG SYSTEM NAME 'NULL   µ' NOT AVAILABLE.
    R; T=0.01/0.01 14:42:14
    access 190 B/A
    B (190) R/O
    190 ALSO = S-DISK
    cmsxgen 100000
    SYSTEM SAVED
    CMSXGEN COMPLETE
    define storage 960k
    STORAGE = 00960K
    CP ENTERED; DISABLED WAIT PSW '00020000 00000000'
    IPL 190
    RELEASE 6 CMS 12/25/78
    savesys cms
    SYSTEM SAVED
    RELEASE 6 CMS 12/25/78
    </code>

    Поздравляю, теперь у вас есть своя CP/CMS система. Чтобы выключить ее, введите в консоли оператора команду shutdown. Когда будете запускать ее снова, выберите warm start.
    PS: Вообще-то, еще много что можно рассказать. Но и так уже простыня получилась.
    Удачных вам IPL-ов!

    PS: кто попробовал установить и не лень отписаться — отпишитесь, пожалуйста.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Pro Core Data for iOS. Глава №2. Теоретическая часть

    Хабралюди, добрый день!
    Сегодня хочу начать вольный перевод книги Михаеля Привата и Роберта Варнера «Pro Core Data for iOS», которую можете скачать по этой ссылке. Каждая глава будет содержать теоретическую и временами практическую часть.

    image

    Содержание:
    • Глава №1. Приступаем (Практическая часть)
    • Глава №2. Усваиваем Core Data
    • Глава №3. Хранение данных: SQLite и другие варианты
    • Глава №4. Создание модели данных
    • Глава №5. Работаем с объектами данных
    • Глава №6. Обработка результатирующих множеств
    • Глава №7. Настройка производительности и используемой памяти
    • Глава №8. Управление версиями и миграции
    • Глава №9. Управление таблицами с использованием NSFetchedResultsController
    • Глава №10. Использование Core Data в продвинутых приложениях


    Вступление

    Многие разработчики, после первого знакомства с Core Data, считают его каким-то запутанным набором классов, который вместо того, чтобы упрощать работу с данными, наоборот, препятствует этому. Возможно это Rails разработчики, привыкшие к написанию динамических методов поиска и позволяющие принятым соглашениям выполнять за них всё грязную работу. Возможно это Java разработчик, который аннотирует Enterprise JavaBeans (EJB) и работает с Plain Old Java Objects (POJO). Кем бы ни были эти люди, чем бы они не занимались, они не воспринимают Core Data Framework таким какой он есть и его способы работы с данными, столько же разработчиков при виде того, как создаются «живые» интерфейсы с использованием Interface Builder кривятся и ухмыляются. Мы уверяем Вас, что Core Data это не очередная машина Рубена Голдберга. Классы в Core Data Framework скорее игроки Бостон Селтикс 1980 года и, когда вы поймете их подходы к игре, лишь тогда сможете оценить всю прелесть и законченность их игры и взаимодействия.

    Знаете ли Вы?
    Рубен Люциус Голдберг (англ. Reuben Lucius Goldberg; 1883—1970) — американский карикатурист, скульптор, писатель, инженер и изобретатель.
    Голдберг более всего известен серией карикатур, в которых фигурирует так называемая «машина Руба Голдберга» — чрезвычайно сложное, громоздкое и запутанное устройство, выполняющее очень простые функции (например, огромная машина, занимающая целую комнату, цель которой — передвижение ложки с пищей от тарелки до рта человека).
    В 1948 году Голдберг получил Пулитцеровскую премию за свои политические карикатуры, а в 1959 году — премию Banshees' Silver Lady Award.
    Голдберг был одним из основателей и первым президентом Национального общества карикатуры. Его именем названа премия Рубена, которой организация награждает карикатурист года. В США ежегодно проходит конкурс машин Руба Голдберга.
    image

    В этой главе будут расписаны предназначения классов Core Data Framework, как по отдельности, так и при совместной их работе. Постарайтесь не спешить прочитать главу целиком. Исследуйте примеры, покопайтесь с ними, вводите код сами (никакого копипаста!) и запускайте на проверку.

    Классы Core Data
    В первой главе мы уже рассмотрели и создали самое простое приложение используя Core Data. Вы видели отрывки кода, какие классы были использованы, какие методы вызывались, в каком порядке этим самые методы вызывались и какие параметры этим методам передавались. Всё это для того делалось, чтобы понять каким образом работает Core Data. Вы слепо следовали тому, что вам говорили делать, возможно в некоторые моменты вы и недоумевали зачем это делается, но продолжали отстукивать на клавиатуре сладкие
    NSManagedObject, возможно вы задавали себе вопрос «А что будет, если сюда подставить другое значение?». Некоторые возможно даже попробовали заменить одно значение на другое, именно они получили что-то отличное от взрыва ;), а кто-то получил то, что и рассчитывал получить.

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

    Знаете ли Вы?
    Премия Тьюринга (англ. Turing Award) — самая престижная премия в информатике, вручаемая Ассоциацией вычислительной техники за выдающийся научно-технический вклад в этой области.

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

    В настоящее время премия спонсируется корпорациями Intel и Google и составляет 250 000 долларов США.

    © Википедия

    Core Data не только справляется с задачей хранения данных, но и делает это элегантно. Чтобы добиться этой элегантности у себя в кода, Вам необходимо понимать Core Data, а не гадать на кофейной гуще о том, как оно работает и вообще почему оно работает. После прочтения данной главы Вы в деталях поймете не только саму структуру Core Data Framework, но и то, каким образом фрэймворк решает сложные проблемы используя небольшой набором классов, делая решения простыми, понятными и элегантными. На протяжении главы мы будем строить и дополнять диаграмму классов Core Data Framework. От Вас не ускользнёт и тот факт, что не все классы будут принадлежать Core Data Framework, некоторые будут импортированы из Foundation Framework. Параллельно с теоретической частью мы будем разрабатывать маленькое приложение, которое будет работать с фиктивными организационными структурами (менеджеры, программисты, начальники, администраторы и тд).

    Откройте XCode и создайте Single View Application:
    image

    Назовите проект OrgChart.
    Подключите в проект Core Data (см. Глава №1). Запустите приложение и убедитесь, что оно не падает.
    image

    На изображении приведенном ниже отображены классы Core Data с которыми мы обычно работаем:
    image

    В нашем коде сохранение данных происходит путём добавления новых NSManagedObject
    в
    NSManagedObjectContext, а получение данных с помощью NSFetchRequest
    класса. Как было показано в Главе №1, среда управления объектами (managed object context) создается и инициализируется при помощи диспетчера хранилищ данных (persistent store coordinator), реализуемого классом
    NSPersistentStoreCoordinator, который в свою очередь определяется моделью данных, реализуемой классом NSManagedObjectModel
    . Оставшаяся часть главы будет посвящена рассмотрению того, каким образом создаются эти классы, как они взаимодействуют между собой и, как их использовать.

    Использующиеся при создании модели данных классы
    Как было ранее упомянуто в Главе №1, все приложения использующие Core Data должны иметь объектную модель хранимых данных. Модель определяет сущности и их свойства. У сущности есть три типа свойств:
    • Атрибуты
    • Отношения
    • Свойства выборки

    Таблица, которую вы видите ниже, показывает различные классы и описание их роли.
    Перебирать классы для лучшего понимая механизма инициализации модели достаточно интересное занятие, но на практике создание модели в XCode требует от вас умения работать мышкой в графическом редакторе моделей, без написания единой строчки кода.
    Наименование классаРоль
    NSManagedObjectModelМодель данных
    NSEntityDescriptionСущность в модели данных
    NSPropertyDescriptionАбстрактное описание свойства сущности
    NSAttributeDescriptionАтрибут сущности
    NSRelationshipDescriptionСсылка одной сущности на другую
    NSFetchedPropertyDescriptionОписание подмножества экземпляров сущностей выбранным по определенному критерию

    Таблица ниже показывает отношения между классами использующимися при определении модели.
    NSManagedObjectContext не ссылается, либо ссылается на несколько объектов сущностей NSEntityDescription
    . Каждая объектная сущность
    NSEntityDescription не ссылается, либо ссылается на несколько объектов NSPropertyDescription
    .
    NSPropertyDescription
    является абстрактным классом с тремя конкретными реализациями:
    • NSAttributeDescription
    • NSRelationshipDescription
    • NSFetchedPropertyDescription
    image

    Этого маленького кол-ва классов будет достаточно для того, чтобы описать любую модель данных, которая будет вами разрабатываться с использованием Core Data Framework. Как описывалось ранее в Главе №1, для создания модели необходимо открыть XCode, выбрать пункт меню File -> New -> New File и указать «Data Model». В этой секции мы создадим модель, которая будет представлять собой организационную структуру компании.
    Создайте новую модель в XCode и назовите её OrgChart. В этой модели данных у организации есть директор (CEO). Для простоты представим, что у человека есть два атрибута: уникальный идентификатор служащего и имя. Теперь мы готовы приступить к определению модели данных.
    Откройте модель данных и создайте новую сущность Organization. Как и человек, организация определяется своим уникальным идентификатором и именем. Добавьте два атрибута сущности Organization. Атрибуты представляют собой постоянные свойства сущности, которые могут содержать значения некоторого типа. Типы данных атрибутов описываются в классе
    NSAttributeType и каждый тип данных налагает некоторые ограничения на сущность. Например, если вы попробуете записать строку в свойство с целочисленным типом данных, то возникнет ошибка.
    Таблица ниже описывает существующие типы:
    Тип атрибута в XCodeТип атрибута в Objective-CObjective-CОписание
    Integer 16NSInteger16AttributeTypeNSNumber16-битное целое
    Integer 32NSInteger32AttributeTypeNSNumber32-битное целое
    Integer 64NSInteger64AttributeTypeNSNumber64-битное целое
    DecimalNSDecimalAttributeTypeNSDecimalNumberЦелочисленное значение по основанию 10
    DoubleNSDoubleAttributeTypeNSNumberОбъектная обёртка типа double
    FloatNSFloatAttributeTypeNSNumberОбъектная обёртка типа float
    StringNSStringAttributeTypeNSStringСтрока символов
    BooleanNSBooleanAttributeTypeBOOLОбъектная обёртка логического типа
    DateNSDateAttributeTypeNSDateДата и время
    Binary dataNSBinaryDataAttributeTypeNSDataДвоичные данные
    TransfCL_Prefix_ormableNSTransfCL_Prefix_ormableAttributeTypeЛюбой нестандартный типЛюбой тип, который может быть переведён в стандартный

    Примечание
    В Главе №5 мы разберем тип TransfCL_Prefix_ormable подробнее. TransfCL_Prefix_ormable-аттрибуты это способ уведомить Core Data о том, что будут использовать нестандартные типы данных и, в процессе сохранения данных в локальное хранилище, мы сообщим, каким образом преобразовать этот тип к одному из уже существующих встроенных.

    Назовём первый атрибут id, а второй name. По умолчанию при создании нового атрибута его тип автоматически устанавливается в Undefined и не позволят проекту быть скомпилированным. Ваша задача выбрать подходящий тип для каждого из создаваемых вами атрибутов сущности. Идентификаторы организации всегда будут целочисленного типа, поэтому выберем Integer 16 в качестве типа для id атрибута. Тип String используем для атрибута name.
    На данном этапе ваш проект должен выглядеть следующим образом:
    image

    Если бы на данном этапе программа была бы запущена, то объектный граф выглядел бы следующим образом:
    image

    На графе видно, что модель данных NSManagedObjectModel
    ссылается на объект сущности
    NSEntityDescription, который называется Organization и использует тип NSManagedObject
    для свойства
    managedObjectClassName. У сущности есть два атрибута. Каждый атрибут содержит два свойства: имя и тип. В первом атрибуте имя id
    и тип
    NSInteger16AttributeType для свойств name
    и
    attributeType
    соответственно.

    Таким же образом создайте вторую сущность с именем Person и двумя атрибутами: id и name. Теперь мы можем создать связь между сущностями Organization и Person и назвать её leader. Создать связь достаточно просто: нажимаем на кнопку "+" в разделе «Relationships», выбираем «Destination» и «Source». Теперь добавим еще одну связь между Person и Person и назовём её employees. Последняя созданная нами связь — это связь типа «один к одному», в то время, как у служащего могут быть несколько подчиненных, а значит и тип связи необходим «один ко многим».
    Откройте панель справа в XCode, как это показано на рисунке:
    image

    И поставьте галочку напротив пункта «Plural: To-Many Relationship»:
    image

    Модель данных выглядит следующим образом:
    image

    Вот как будет выглядеть объектный граф, когда модель будет загружена:
    image
    Данный граф не является графом объектов, которые Core Data хранит, это всего лишь отображение того, как выглядит модель в глазах Core Data.
    Типичный способ загрузки модели данных Core Data выглядит следующим образом:
    <code class="objectivec">NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"OrgChart" withExtension:@"momd"];
    
    _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    </code>

    Знание того, каким образом представлены объекты модели в Core Data, в основном не очень полезное, разве что вы занимаетесь написанием собственного хранилища данных или заинтересованы в генерировании модели данных программно на этапе выполнения. Аналогию можно провести с созданием программно UIView, вместо того, чтобы использовать готовые элементы предоставляемые Interface Builder'ом. Однако глубокое понимание того, каким образом работает Core Data, позволит вам предсказывать и избегать сложностей, проблем, и приведёт к решению трудностей креативным и элегентным способом.

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

    Продолжение следует...

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

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    STM32 + EmBlocks — мигаем светодиодами

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

    Подключаем аноды светодиодов к пинам PB5 и PB6, катоды через резсторы в 390 Ом к земле.

    Итак, если еще не скачали EmBlocks, сделайте это. Распакуйте в любой удобный каталог и запускайте.
    Создаем проект, выбрав в меню «File->New->Project...»
    В категории Projects выбираем «STmicro-Arm».

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

    В окне выбора компилера ничего не трогаем и двигаем дальше.
    В окне выбора процессора из первого списка выбираем «STM32F10x_md» т.к. STM32F103C8 принадлежит к семейству F1 и содержит 64к FLASH, что относит его к medium density девайсам.
    Если будете использовать ColinkEx, то выбираем в следующем окне конкретное название процессора, это нужно для прошивки утилитой CoFlash.
    Если будете пользоваться ST-Link, то можно не трогать.
    Галка «Create hex file» отвечает за создание .hex на выходе вместо .elf файла. ColinkEx принимает и те и другие, а вот ST-Link Utility только .hex

    Жмем Finish. Мастер предложит выбрать отладчик и настроить его. Причем дважды — для цели Debug, а затем для Release… Если будете использовать другой, нажмите отмену и выберите другой отладчик. О других отладчиках расскажу как-нибудь в другой раз.
    По-умолчанию предлагается ST-Link, нас это устраивает, поэтому просто жмем Ok дважды для каждой цели (Debug, Release)
    Все, болванка проекта готова. Если теперь нажать F7, проект скомпилируется и готов к прошивке с напоминанием, которое уже учтено в настройках Release цели.

    Разберем структуру проекта:

    Все файлы проекта автоматически раскладываются по папкам Sources, Headers и ASM Sources для ,.h и .S файлов соответственно.

    В папке Sources у нас есть подпапка cmsis_boot с файлом библиотеки CMSIS.
    В подпапке stm_lib\src у нас уже лежит пара файлов, которые нужны практически в любом проекте:
    stm32f10x_gpio.c
    stm32f10x_rcc.c

    Это части StdPeriph Library для работы с GPIO и системой тактирования.
    В подпапке Src лежит файл main.c — заготовка для нашей программы.

    В папке Headers заголовки, разложенные по точно таким же папкам.
    В дальнейшем нужные части StdPeriph Library мы будем добавлять в подпапки stm_lib\inc и stm_lib\src и включать в проект, щелкнув правой кнопкой по названию и выбрав «Add files...» или «Add files recursively...». Но сегодня нам это не понадобится.

    За запуск микроконтроллера отвечает файл startup_stm32f10x_md.S, в папке ASM Sources\cmsis_boot\startup.
    Скрипт линкера лежит в папке Others и называется gcc_arm.ld

    Cо структурой проекта мы бегло познакомились, пора писать код, ради которого и затевали дело.
    Окрываем файл Sources\Src\main.c и заменяем текст в нем на такой:
    <code>#include <stm32f10x.h>
    #include <stm32f10x_conf.h>
    
    #include <stm32f10x_rcc.h>
    #include <stm32f10x_gpio.h>
    #define RCC_GPIO RCC_APB2Periph_GPIOB
    #define LED_PORT GPIOB
    #define LED1_PIN GPIO_Pin_5
    #define LED2_PIN GPIO_Pin_6
    
    void Delay(volatile uint32_t nCount) {
    	for (; nCount != 0; nCount--);
    }
    
    int main(void) {
    	/* SystemInit() уже отработала в startup_stm32f10x_md_vl.S */
    
    	GPIO_InitTypeDef GPIO_InitStructure;
    
    	RCC_APB2PeriphClockCmd(RCC_GPIO, ENABLE);
    
    	GPIO_InitStructure.GPIO_Pin = LED1_PIN | LED2_PIN;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    
    	GPIO_Init( LED_PORT , &GPIO_InitStructure);
    
    	LED_PORT->ODR ^= LED2_PIN;
    	while (1) {
    		LED_PORT->ODR ^= LED2_PIN;
    		LED_PORT->ODR ^= LED1_PIN;
    		Delay(0x7FFFF);
    	}
    
    	return 0;
    }</code>
    Мы определили макросы RCC_GPIO, LED_PORT, LED_PIN1 и LED_PIN2, изменив которые, мы можем подключить светодиоды к пинам другого порта.

    В функции main() заполняем структуру GPIO_InitStructure, настраивая пины PB5 и PB6 на работу в режиме PushPull с максимальной частотой 50MHz.
    Затем инвертируем состояние LED_PIN2, чтобы светодиоды перемигивались и в цикле переключаем их с небольшой задержкой.

    Жмем F7, убеждаемся, что проект собрался без ошибок
    Build
    Подключаем отладчик ST-Link/v2 к плате и подаем на нее питание например через USB, сняв перемычку P2, чтобы ПК не пытался определить плату как USB девайс, а просто подал питание. Жмем F6, чтобы прошить с помощью ST-Link/V2 или выбираем «Tools->Flash w ST-Link/V2» ждем несколько секунд и если все сделали правильно, то светодиоды начнут моргать попеременно, чего мы и добивались:


    Довольно просто, неправда ли?

    Весь процесс занимает примерно минуту. Если у вас все же не получилось, скачайте проект и сравните с тем, что получилось у вас.
    Для другой платы изменится только выбор процессора из списка, если он отличается и макроопределения светодиодов, если он подключены к другому порту.
    Например, для STM32VLDiscovery:
    <code>#define RCC_GPIO RCC_APB2Periph_GPIOC
    #define LED_PORT GPIOC
    #define LED1_PIN GPIO_Pin_8
    #define LED2_PIN GPIO_Pin_9
    </code>


    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Из песочницы] Три правила хорошего программирования

    В последнее время я видел мало действительно хорошего кода, много посредственного и очень много — плохого. (Много того, что я писал раньше — особенно, когда я только начинал — относится к последним, увы.) Читая случайные статьи в интернете и профессиональные книги, я пришел к выводу, что писать хороший код — легко. Невероятно трудно, но в то же время легко. На самом деле, это настолько просто, что сводится к трем правилам.

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

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

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

    Ваш компилятор (или интерпретатор) может обрабатывать абсолютно разные стили кода. Для него n и numberOfObjects — это одно и тоже. Для людей — нет. Они будут долго вчитываться в код, даже если предназначение переменной кажется вам очевидным.

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

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

    Пишите код, понятный людям.

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

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

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

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

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

    Не повторяйте себя.

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

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

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

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

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

    Каждый фрагмент вашего кода должен выполнять одну задачу.

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



    Перевод статьи Good Programming in 3 Simple Rules.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Из песочницы] Создание автономного робота Frank. Часть первая

    image

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

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

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



    image

    Началось все с выбора платформы, на основе которой можно было бы построить робота. На тот момент мне было все равно, будут ли у него ноги, колеса или другие способы передвижения. Я решил начать с одной из платформ компании Lynxmotion, но у них не было в наличии достаточного количество серво-моторов, чтобы отправить мне заказ. В тот момент я познакомился с русскими товарищами из компании Brain Corporation, которая находится в Сан Диего, и съездив к ним в офис, понял, что надо начинать с простого — Lego Mindstorms. Это достаточно простая платформа, понятная подросткам, но позволяющая программировать, при желание, на Python и C++.

    У меня оставалась неделя в Лос Анджелесе до моего отъезда в Москву. На всякий случай, я заказал пару наборов из Lego Technic и собственно сам набор Lego Mindstorms NXT2.0. Почитав несколько интересных статей про Arduino и другие, похожие системы, я заказал несколько наборов, которые включали в себя компоненты для начинающих, серво моторы и крепления серво моторов для Lego.

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

    image

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

    Я решил использовать моторы HiTech вместо тех, что шли с Lego, и вместо NXT Brick использовать другой контролер — Arduino Uno. Подключив серво моторы к PWM выходам Arduino, и проверив, что все работает, я начал заново собирать своего «Фрэнка». Моторы вместе с креплением все еще были достаточно большие, но измененный форм-фактор, позволил их разместить в корпусе внедорожника. Пришлось пожертвовать подвеской, но в будущем, когда дойдет время до езды на улице, я что-нибудь придумаю.

    image

    image

    И так, платформа собрана. Пришло время делать самое интересное — напичкать Фрэнка электроникой и заставить его двигаться. Для тестирования того, что все компоненты работают как надо, я взял Arduino, обычную плату для прототипирования. У каждого серво-мотора есть три кабеля — красный, черный и желтый. Черный кабель это земля. При подключение Arduino необходимо, чтобы земля у Arduino и серво-моторов была замкнута между собой. Поэтому все черные кабеля от серво-моторов, grd выход из Arduino и минуc у батареи, которая питает серво-моторы мы соединяем вместе. Далее, плюс серво-моторов (красный кабель) и плюс батареи мы соединяем вместе, но не подключаем к Arduino. Для того, чтобы Arduino функционировал без проблем, необходимо изолировать питание серво-моторов и питание Arduino. Для этого я использую разные источники питания для моторов и Arduino. Если питание одно, то между плюсом и землей у каждого серво-мотора надо припаять конденсатор — это избавит от лишнего «шума» в плате.

    Убедившись, что пресет «Servo->Sweep» в Arduino работает, я принялся спаивать небольшую схему на базе Arduino Proto Shield. Конечно, из-за того, что это был мой первый опыт с паяльником в руках — плату я благополучно угробил, не заметив, что некоторые контакты связаны с «землей», а значит и между собой. Теперь жду, когда придут новые платы для экспериментов.

    На данный момент, это то, где прогресс с моими экспериментами остановился на сегодняшний день. Что я планирую делать дальше, когда придут дополнительные компоненты?

    Итак! На этой неделе мне должны доставить 3 солнечные батареи по 3W каждая, две Arduino Proto Shield (на тот случай если я еще одну плату уничтожу), Li-Po батарея 2LIR18650-PCB-LD, Lipo Rider компании Seeedstudio.

    Так же в наличии у меня остались различные ультразвуковые датчики, 2 CMOS камеры и BeagleBone Black. Что же из этого всего может получиться?

    Солнечные батареи, Li-Po батарея и Lipo Rider будут обеспечивать автономную работу. При падении напряжения, робота можно будет переводить в «спящий» режим, пока батареи заряжаются.

    Две камеры, ультразвуковые сенсоры и возможно лазерный дальномер (когда я придумаю достаточно дешевое решение) будут обрабатываться BeagleBone Black для построения «картины окружающего мира». Учитывая то, что процесс зрительного восприятия у людей многоуровневый (различные уровни наших нейронных сетей обрабатывают разные свойства изображения), то мне пришла идея использовать несколько плат BeagleBone Black или Parallela, соединенных иерархически. Каждая плата будет выполнять свой алгоритм, максимально утилизирующий мощность процессора и количество свободной памяти, передавая данные дальше по цепочке для дальнейшей обработки. Таким образом, можно обрабатывать и другие сенсоры. В результате, получится большая сеть компонентов, которая, как живой организм, управляет автономным роботом.

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

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

    США:
    1) Основной ресурс в Америке, как не удивительно это Amazon.com. Там можно купить все, что угодно.
    2) Newark.com — тут можно купить любые компоненты для сбора микросхем.
    3) Lynxmotion — тут можно купить запчасти и готовые роботы.
    4) Mindsensors — различные сенсоры для Lego и других платформ. Есть много чего для Arduino.
    5) Trossen Robotics — пожалуй, самая крутая платформа для разработки роботов. Тут же можно купить серво-моторы, запчасти, микросхемы и так далее.

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

    1) Electronshik — Единственное, что я пока нешел. Тут есть далеко не все, но все, что мне нужно было на данный момент.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Международная популярность Сноудена — миф или реальность? Результаты глобального мониторинга социальных медиа

    Эдварда Сноудена не существует и о нем говорят только в России. «Сноуден — предатель, враг и изменник», — считают жители США. «Сноуден — международный герой и пример для подражания», — говорят… ну где-то наверняка говорят, думали мы. Когда мы приступали к работе над новой задачей, нам казалось, что тема Эдварда Сноудена заинтриговала весь мир. Поэтому задача, поставленная нашими партнерами из фонда «Vox Populi», специализирующегося на исследованиях общественного мнения в социальных медиа, казалась нам довольно простой: оценить интерес населения к ситуации по Сноудену в мире, и в России и США в частности. Но мониторинг соцмедиа для социологических исследований — сущность новая, а потому вдвойне интересная: во-первых, никогда не знаешь, какой именно результат получишь; во-вторых, восхищаешься возможностями социовселенной, созданной человечеством. Результат и в этот раз получился несколько бОльшим и довольно неожиданным: мы проанализировали многоязычный поток сообщений из 230 (!) стран мира. О том, как мы разделяли по языкам и геолоцировали это царство Вавилонское — под катом.


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

    Уже тогда стала очевидной разница в ментальности людей в использовании соцмедиа: например, для французов процент геолокации (геопривязки) сообщений Twitter на уровне 75%, для венесуэльцев — 80%, а в России — всего 44%.

    Первоначальный анализ ситуации со Сноуденом показал, что интерес к теме — общемировой и многоязычный. А значит мы могли на практике оценить достоинства (или недостатки) новых расширенных модулей геолокации и автоопределения языка, на разработку которых были брошены значительные силы разработчиков и лингвистов.
    Почему при геолокации нам так важно понимать язык сообщения? Всё дело в том, что для определения местоположения автора мы анализируем не только данные профиля, но и его посты, твиты, комментарии и т.п. То есть, мы учитываем гео-данные из профиля автора, обновляем их при поступлении каждого нового сообщения. Учитываем гео-метки к сообщениям автора. Учитываем гео-информацию внутри сообщений. Делаем связку профиля автора с его профилями в других соцсетях, и учитываем гео-данные там. Прогоняем это все через наши гео-словари, чтобы привести данные из разных форматов указания гео к единому виду и сделать связку город-регион-страна.

    Тема Сноудена позволила исследовать «температуру по больнице» для геолокации соцмедиа для всего мира. Для анализа использовались сообщения Twitter и Facebook, плюс ВКонтакте для русскоязычных сообщений. Итог: геолокация определяется для 57.8% от всех авторов на уровне страны и 41.4% с точностью до города.

    Фактография по итогам исследования (данные с 1 по 20 августа):
    — свыше 600 000 сообщений;
    — 230 000 уникальных авторов;
    — из 230 стран мира (8 000 населенных пунктов)!


    Вот такая вот неожиданность, думаю, для многих из нас — оказывается в мире больше 200 стран (и территорий). Например, есть такие вот красивые названия: Уоллис и Футуна, Святая Люсия, Буве, Майотта, Кирибате и даже Ниуэ :-)

    Для анализа сообщений использовались написания фамилии Сноуден в разных странах:
    США, Англия, Германия, Франция, Польша, Чехия, Венгрия, Румыния, Молдавия и др.: Snowden
    Болгария: ЕДУАРД СНОУДЪН
    Белоруссия, Украина: Эдвард Сноуден
    Казахстан: Эдвард Сноувден
    Словакия: Edward Snowden, Edwardovi Snowdenovi
    Македония: Едвард Сноуден
    Сербия и ex-Югославия: Edward Snowden, Едвард Сновден Албания Edvard Snovden
    Азербайджан: Edvard Snouden
    Греция: ?????????

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

    U r wrong Obama. Snowden IS a patriot. It is u who r the traitor to the United States
    Источник: twitter.com | автор: Jim Hackney | США, Спрингфилд | 14.08
    21:05:34

    В пул также попали сообщения на арабском, иероглифических или местных языках, например:

    ???? ???? Lavabit ?????? ?????????? ????? ????????? ??? Snowden: ?? ???? ?????? ?? ????? ?? ????? ????… t.co/2FzhZME3wJ #news
    Источник: twitter.com | автор: TAlbahussain | Дублей: 49 Саудовская Аравия, Эр-Рияд | 10.08 18:46:52

    Quyet di?nh cho? xem mua sao bang. Haiz, la?o Snowden rat "dang yeu" nha, muon giet qua B-)
    Источник: facebook.com | автор: Kim Eun Won | Республика Корея, Сеул |
    12.08 18:45:38

    RT @supinya: ???? #Snowden ?????????????????????????? ??????????????? ???????????????
    ?????????????????????????????????????????????????????? ???????????
    Источник: twitter.com | автор: Natdanai | Таиланд, Пхукет | 13.08 15:36:58

    Такие сообщения использовались для оценки интереса к теме, но не тонализировались (не проводились через модуль определения тональности сообщения).

    Результаты исследования по теме Сноудена опубликованы в «Коммерсанте».

    Немного жаль, что не успели расширить на мировую карту наш картографический модуль, заточенный под регионы России, США и Европу.

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

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


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

    image
    Нормальное распределение (распределение Гаусса) всегда играло центральную роль в теории вероятностей, так как возникает очень часто как результат воздействия множества факторов, вклад любого одного из которых ничтожен. Центральная предельная теорема (ЦПТ), находит применение фактически во всех прикладных науках, делая аппарат статистики универсальным. Однако, весьма часты случаи, когда ее применение невозможно, а исследователи пытаются всячески организовать подгонку результатов под гауссиану. Вот про альтернативный подход в случае влияния на распределение множества факторов я сейчас и расскажу.

    Краткая история ЦПТ. Еще при живом Ньютоне Абрахам де Муавр доказал теорему о сходимости центрированного и нормированного числа наблюдений события в серии независимых испытаний к нормальному распределению. Весь 19 и начало 20 веков эта теорема послужила ученым образцом для обобщений. Лаплас доказал случай равномерного распределения, Пуассон – локальную теорему для случая с разными вероятностями. Пуанкаре, Лежандр и Гаусс разработали богатую теорию ошибок наблюдений и метод наименьших квадратов, опираясь на сходимость ошибок к нормальному распределению. Чебышев доказал еще более сильную теорему для суммы случайных величин, походу разработав метод моментов. Ляпунов в 1900 году, опираясь на Чебышева и Маркова, доказал ЦПТ в нынешнем виде, но только при существовании моментов третьего порядка. И только в 1934 году Феллер поставил точку, показав, что существование моментов второго порядка, является и необходимым и достаточным условием.

    ЦПТ можно сформулировать так: если случайные величины независимы, одинаково распределены и имеют конечную дисперсию отличную от нуля, то суммы (центрированные и нормированные) этих величин сходятся к нормальному закону. Именно в таком виде эту теорему и преподают в вузах и ее так часто используют наблюдатели и исследователи, которые не профессиональны в математике. Что в ней не так? В самом деле, теорема отлично применяется в областях, над которыми работали Гаусс, Пуанкаре, Чебышев и прочие гении 19 века, а именно: теория ошибок наблюдений, статистическая физика, МНК, демографические исследования и может что-то еще. Но ученые, которым не достает оригинальности для открытий, занимаются обобщениями и хотят применить эту теорему ко всему, или просто притащить за уши нормальное распределение, где его просто быть не может. Хотите примеры, они есть у меня.

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

    Второй пример: изменения финансовых показателей. Исследования изменения курса акций, котировок валют, товарных опционов требует применения аппарата математической статистики, а особенно тут важно не ошибиться с видом распределения. Показательный пример: в 1997 году нобелевская премия по экономике была выплачена за предложение модели Блэка — Шоулза, основанной на предположении нормальности распределения прироста фондовых показателей (так называемый белый шум). При этом авторы явно заявили, что данная модель нуждается в уточнении, но всё, на что решилось большинство дальнейших исследователей – просто добавить к нормальному распределению распределение Пуассона. Здесь, очевидно, будут неточности при исследовании длинных временных рядов, так как распределение Пуассона слишком хорошо удовлетворяет ЦПТ, и уже при 20 слагаемых неотличимо от нормального распределения. Гляньте на картинку снизу (а она из очень серьезного экономического журнала), на ней видно, что, несмотря на достаточно большое количество наблюдений и очевидные перекосы, делается предположение о нормальности распределения.

    Здесь очевидно не соответствие нормальному закону

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

    Общее у распределений из этих примеров – наличие так называемого «тяжелого хвоста», то есть значений, далеко лежащих от среднего, и заметной асимметрии, как правило, правой. Рассмотрим, какими еще, кроме нормального могли бы быть такие распределения. Начнем с упоминаемого ранее Пуассона: у него есть хвост, но мы же хотим, чтобы закон повторялся для совокупности групп, в каждой из которых он наблюдается (считать размер файлов по предприятию, зарплату по нескольким городам) или масштабировался (произвольно увеличивать или уменьшать интервал модели Блэка — Шоулза), как показывают наблюдения, хвосты и асимметрия не исчезают, а вот распределение Пуассона, по ЦПТ, должно стать нормальным. По этим же соображениям не подойдут распределения Эрланга, бета, логонормальное, и все другие, имеющие дисперсию. Осталось только отсечь распределение Парето, а вот оно не подходит в связи с совпадением моды с минимальным значением, что почти не встречается при анализе выборочных данных.

    Распределения, обладающее необходимыми свойствами, существуют и носят название устойчивых распределений. Их история также весьма интересна, а основная теорема была доказана через год после работы Феллера, в 1935 году, совместными усилиями французского математика Поля Леви и советского математика А.Я. Хинчина. ЦПТ была обобщена, из нее было убрано условие существования дисперсии. В отличие от нормального, ни плотность ни функция распределения у устойчивых случайных величин не выражаются (за редким исключением, о котором ниже), все что о них известно, это характеристическая функция (обратное преобразование Фурье плотности распределения, но для понимания сути это можно и не знать).
    Итак, теорема: если случайные величины независимы, одинаково распределены, то суммы этих величин сходятся к устойчивому закону.

    Теперь определение. Случайная величина X будет устойчивой тогда и только тогда, когда логарифм ее характеристической функции представим в виде:

    Stable law fCL_Prefix_ormula



    где params.

    В самом деле, ничего сильно сложного здесь нет, просто надо объяснить смысл четырех параметров. Параметры сигма и мю – обычные масштаб и смещение, как и в нормальном распределении, мю будет равно математическому ожиданию, если оно есть, а оно есть, когда альфа больше одного. Параметр бета – асимметрия, при его равенстве нулю, распределение симметрично. А вот альфа это характеристический параметр, обозначает какого порядка моменты у величины существуют, чем он ближе к двум, тем больше распределение похоже на нормальное, при равенстве двум распределение становиться нормальным, и только в этом случае у него существуют моменты больших порядков, также в случае нормального распределения, асимметрия вырождается. В случае, когда альфа равна единице, а бета нулю, получается распределение Коши, а в случае, когда альфа равна половине, а бета единице – распределение Леви, в других случаях не существует представления в квадратурах для плотности распределения таких величин.
    В 20 веке была разработана богатая теория устойчивых величин и процессов (получивших название процессов Леви), показана их связь с дробными интегралами, введены различные способы параметризации и моделирования, несколькими способами были оценены параметры и показана состоятельность и устойчивость оценок. Посмотрите на картинку, на ней смоделированная траектория процесса Леви с увеличенным в 15 раз фрагментом.



    Именно занимаясь такими процессами и их приложением в финансах, Бенуа Мандельброт придумал фракталы. Однако не везде было так хорошо. Вторая половина 20 века прошла под повальным трендом прикладных и кибернетических наук, а это означало кризис чистой математики, все хотели производить, но не хотели думать, гуманитарии со своей публицистикой оккупировали математические сферы. Пример: книга «Пятьдесят занимательных вероятностных задач с решениями» американца Мостеллера, задача №11:



    Авторское решение этой задачи, это просто поражение здравого смысла:


    Такая же ситуация и с 25 задачей, где даются ТРИ противоречащих ответа.

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

    Моделирование устойчивых случайных величин. Так как все познается в сравнении, то напомню сначала наиболее удобный, с точки зрения вычислений, метод генерирования нормальной величины (метод Бокса – Мюллера): если image– базовые случайные величины (равномерно распределены на [0, 1) и независимы), то по соотношению imageполучится стандартная нормальная величина.

    Теперь зададим заранее альфу и бету, пусть V и W, независимые случайные величины: V равномерно распределена на image, W экспоненциально распределена с параметром 1, определим imageи image, тогда по соотношению:
    image
    получим устойчивую случайную величину, для которой мю равна нулю, а сигма единице. Это так называемая стандартная устойчивая величина, которую для общего случая (при альфа не равном единице), просто достаточно помножить на масштаб и прибавить смещение. Да, соотношение сложнее, но оно все равно достаточно простое, чтобы его использовать даже в электронных таблицах (Ссылка). На рисунках снизу показаны траектории моделирования модели Блэка — Шоулза сперва для нормального, а затем для устойчивого процесса.





    Можете поверить, изменения цен на биржах больше похож на второй.

    параметров устойчивого распределения. Так как вставлять формулы на хабре достаточно сложно, я просто оставлю ссылку на статью, где подробно разбираются всевозможные методы для оценки параметров, или на мою статью на русском языке, где приводятся только два метода. Также можно найти замечательную книгу, в которой собрана вся теория по устойчивым случайным величинам и их приложениям (Zolotarev V., Uchaikin V. Stable Distributions and their Applications. VSP. M.: 1999.), или ее чисто научный русский вариант (Золотарев В.М. Устойчивые одномерные распределения. – М.: Наука, Главная редакция физико-математической литературы, 1983. – 304 с.). В этих книгах также присутствуют методы для вычисления плотности и функции распределения.

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

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Делегирование

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

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

    Теперь основной фронт проблемы – операционный завал руководителя, который зачастую является и sales менеджером, и маркетологом, и проект-менеджером, и возможно ещё и кодит или дизигнит время от времени и бухгалтерское дело пытается изучить. Экий многорукий многоног.
    Для начала определим – что такое операционный завал и откуда «растут ноги?»
    Операционка – это те дела, которые требуют вашего вмешательства как правило в режиме «ПРЯМВОТЩАС» и «СРОЧНО!!!11». Это рутина типа подсчёта налогов, закрытие квартала, начисление заработных плат, выставление счетов, ведение проектов и мыслей о светлом завтра.

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

    Шок терапия номер два.

    «Страх» многих руководителей «если я найму спеца, он уведёт у меня клиентов, команду/программиста/дизайнера»… Да, такое может быть. И это нормально. Поймите рынок огромен и в нём целая куча крутых специалистов различных областей и клиентов ещё больше. Предположим, что вы уже сделали пару шагов, наняли sales, возможно даже двух, и даже бухгалтера – проекты вы продолжаете вести сами. Это ещё одна огромная ошибка начинающего руководителя. Пусть проектами занимается ПМ. Курируйте менеджера, а не его проект. Это снимет с вас ещё одну огромную головную боль. Чуть позже, я бы рекомендовал взять ещё одного ПМ (двоих как правило хватает очень и очень на долго, с условием, что они клёвые).
    Вот, голова болит уже меньше, и теперь, ваша задача найти хорошего, опытного, специалиста под названием руководитель отдела продаж. Ни кто не спорит и не говорит, что вы, делаете это плохо, дело в том, что это необходимо делегировать. Это как раз та тонкая грань между вами – специалистом в продажах и им профессионалом в них же. Объем его знаний, успешных практик и методик несравненно выше вашего. Пользуйтесь.

    Итого три продажника – это уже маленькая, но армия, способная приносить клиентов и вполне рентабельные проекты.
    Два ПМ – ведущие проекты, курирующие задачи, помогающие команде.
    Бухгалтер – ведущий львиную долю вопросов, от которых можно сойти с ума.
    Итого, плюс шесть человек. Их ненужно нанимать вот прямо сию секунду, их нужно нанимать в течении 4-6-8 месяцев, в зависимости от вашей загруженности и возможностей. И вот, в тот самый момент, когда у вас заработал новый механизм – вы можете заняться наконец-то тем, чем и должен заниматься руководитель – думать, куда дальше идти. Стратегия, анализ, тактика. Вот ваши три основные поля битвы на относительно долгое время.
    Сей рецепт, не есть панацея и годен лишь тем веб-студиям, чьи руководители находятся в состоянии которое граничит с безумием.
    Благодарю вас за прочтение, и желаю удачи. Делегируйте. Особенно рутину.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Android — живые обои на OpenGL ES 2.0 с упрощенным эффектом DOF

    Идеей для создания приложения послужило видео, в свою очередь вдохновленное дизайном Deus Ex: Human Revolution, а именно его элементами с осколками стекла. За пару дней созрело конечное видение сцены и в итоге за выходные была создана первая версия готового приложения.
    photo title_zps88207f0f.jpg


    Построение сцены

    Сцена предельно простая. Она состоит из собственно плавно вращающихся осколков стекла, зависших в воздухе. Осколки разделены на 2 группы — находящиеся вблизи и вдалеке. Объекты вдалеке размыты для придания сцене дополнительного объема. Также есть размытый задний фон произвольного цвета. Камера движется влево-вправо согласно движения пальца по экрану, и таким образом осколки двигаются.
    Технически это реализовано так: Осколки стекла размещены по цилиндру вокруг камеры. Осколки, расположенные дальше определенного расстояния, отрисовываются в отдельную текстуру и размываются. Вместе с ними же рисуется и фон. Рисуются сперва размытые объекты вдали и поверх них уже рисуются осколки, находящиеся ближе к камере.
    Вот таким нехитрым способом мы и реализовали упрощенный эффект depth-of-field (DOF), которого вполне достаточно для даной сцены. Полноценная же реализация DOF несколько сложнее и более ресурсоемкая. Для этого потребовалось бы рендерить в отдельные текстуры карту глубины сцены, готовую сцену, и ее же еще раз но с размытием. И затем уже рисовать на экран одновременно размытую и четкую сцену, смешивая их согласно глубины и параметров фокуса камеры.

    Реализация

    Так как все объекты в сцене прозрачные, то весь рендеринг производится с различными blending mode. При этом запись в depth buffer не ведется для того, чтобы прозрачные стекла не отсекали объекты за ними. Так как самих стекол немного, то это не вызывает слишком большой повторной отрисовки пикселей. Для создания бликов и отражений объекты осколков рисуются с cubemap размером 128х128.

    Порядок отрисовки заднего плана:
    1. Очитска FBO с glClearColor нужным цветом.
    2. Поверх рисуется маска на весь размер фрейм-буфера. Таким образом получаем декоративные цветные размытые пятна для фона вместо сплошного цвета.
    3. Затем отрисовываются стекла для заднего плана. Разрешение 256х256, изображение довольно сильно пикселировано.
    4. Размытие всего заднего плана. Низкое разрешение заднего фона практически не заметно.
    photo bg_zps70ce1ce5.jpg

    Отрисовка основной сцены и компоновка двух планов:
    1. Очистка экрана.
    2. Отрисовка заднего плана.
    3. Рендеринг стекол переднего плана.
    Эта отрисовка производится без записи в depth buffer, так как все объекты прозрачные.
    photo fg_zps0f2e8074.jpg

    Размытие объектов на заднем плане

    Размытие реализовано последовательной отрисовкой изображения между двумя фрейм-буферами специальным шейдером. Шейдер может делать горизонтальное либо вертикальное размытие, это задается параметрами. Этот способ размытия называется ping-pong rendering. Суть его заключается в том, что сперва текстура из фрейм-буфера А отрисовывается с горизонтальным размытием в фрейм-буфер B, а затем наоборот из В в А, но с вертикальным размытием. Эту процедуру можно повторять необходимое количество итераций для достижения необходимого качества размытия исходного изображения. Пример реализации этого эффекта постпроцессинга был взят давно из какого-то примера bloom, ссылку к сожалению не могу найти.
    Примечательно, что современные телефоны и планшеты (и даже весьма старенькие устройства, тоже) могут успевать проводить даже не одну, а несколько итераций размытия достаточно быстро. На практике оказалось, что Nexus 10 выдает стабильные 50-40 fps даже при 6-8 проходах размытия текстуры 256х256, причем одним проходом является полное — горизонтальное + вертикальное размытие.
    Подбирая достаточно компромиссное соотношение разрешения текстуры, количества проходов и качества размытия, остановились на трех итерациях и разрешении 256х256.

    Mali

    В предыдущей статье я закинул камень в огород nVidia. Это не потому, что я просто так недолюбливаю nVidia — я точно также недолюбливаю любых других производителей железа, которые предоставляют глючные драйвера к своим GPU. Вот, например, при разработке описываемых живых обоев столкнулись с проблемой на Nexus 10. Проблема заключается в некорректном рендеринге в текстуру, причем проявляется это только при изменении ориентации устройства. Каким образом ориентация планшета может влиять на рендеринг в текстуру, для нас остается загадкой, но это факт.
    Сперва, для того чтобы убедиться что я просто упустил какой-то нюанс при инициализации контекста, написал вопрос на Stack Overflow: stackoverflow.com/questions/17403197/nexus-10-render-to-external-rendertarget-works-only-in-landscape И вот тут стоит похвалить сотрудников ARM за работу их тех. поддержки. Через пару-тройку дней я получил письмо от инженера ARM в котором он предложил дать запрос об этом баге на Mali Developer Center. Я подготовил простенькое тестовое приложение и описал шаги для воспроизведения ошибки: forums.arm.com/index.?/topic/16894-nexus-10-render-to-external-rendertarget-works-only-in-landscape/page__gopid__41612. И через всего лишь 4(!) дня получил ответ о том, что действительно есть баг в текущей версии видео-драйвера для Nexus 10. Самое интересное, что ARM предложил workaround для решения моей проблемы, который чудесным образом помог — надо просто вызывать glViewport() после glBindFramebuffer(). За такую работу тех. поддержки ARM им памятник при жизни надо поставить — сотрудник ARM не поленился найти мой e-mail (а он на Stack Overflow не указан), и инженеры тех. поддержки ARM нашли и решили проблему быстрее чем я даже ожидал.
    Всех интересующихся качеством Android на Nexus 10 прошу голосовать за соответствующий баг в трекере Гугла: code.google.com/p/android/issues/detail?id=57391

    Результат

    Скачать программку можно с Google Play по ссылке: play.google.com/store/apps/details?id=org.androidworks.livewallpaperglass

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

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Видеообзор ноутбука Acer Aspire R7


    Acer Aspire R7 — гибридный ноутбук, оснащаюшенный специальным шарнирным механизмом Ezel, позволяющим использовать устройство в четырех конфигурациях: планшет, ноутбук, режим просмотра и специальный режим Ezel, который позволяет придвинуть экран ближе к клавиатуре, закрывая собой тачпад, который располагается у Aspire R7 в верхней части рабочей области.

    Новинка оснащается глянцевым IPS дисплеем с диагональю 15,6 дюйма и разрешением 1920x1080. Работают новинки на низковольтных процессорах Intel Core i7 или i5, а за графику отвечают видеокарты NVIDIA GeForce GT 750M или Intel HD4000 (в зависимости от модели).

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Из песочницы] Поиск уязвимостей у хабросайтов

    Время было вечером, делать было нечего… Было решено удивить хабражителей. Но как? Банальные поиски уязвимостей на известных сайтах уже никому не интересны. Чтож, значит включим фантазию… Ведь у пользователей тоже есть сайты! Срочно проверить их на стойкость!

    Как все происходило:

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

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

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

    Расчехлен любимый питон, включено воображение, написано вот это:
    <code class="python">import urllib2, re
    
    start = "первый пользователь"
    
    """ Выкачиваем страничку первого пользователя, и парсим с нее имена первых жертв """
    page = urllib2.urlopen("http://habrahabr.ru/users/"+start+"/subscription/followers/").read()
    names = re.findall('<div class="username"><a href="/users/(.*?)/">(.*?)</a></div>', page)
    
    """ рекурсивная функция, которая, вызывая себя в себе, будет ходить по сайту в поисках новых жертв"""
    
    def going(names):
        for name in names:
            page = urllib2.urlopen("http://habrahabr.ru/users/"+name[0]+"/subscription/followers/").read()
            names = re.findall('<div class="username"><a href="/users/(.*?)/">(.*?)</a></div>', page)
    
    """ и писать новых жертв в файл """
    
            base = open('habrs.txt', 'a')
            writed = 0
            for item in names:
                base.write(item[0]+"\r\n")
                writed = writed + 1
            print 'Saved habrs\'s: '+str(writed)
        going(names)
    
    going(names)
    </code>

    После некоторого времени работы было спарсено достаточное количество хабралюдей(около 10к). Ясно понятно, что большая часть этих людей повторяются… Что же делать?

    Пункт второй: Уникализировать
    Подумав, я решил, что грузить питон будет несправедливо. Поэтому в мой мозг полезла идея об array_unique из . Подумано — сделано.

    Весь скрипт заключается в открывании-закрывании файла, но зато сама уникализация в одну функцию.
    <code class="php"><?php
    $arr = file_get_contents("habrs.txt");
    $arr = explode("\r\n", $arr);
    $arr = array_unique($arr);
    $string = "";
    foreach($arr as $name){
    	$string = $string.$name."\r\n";
    }
    file_put_contents("habrs2.txt", $string);
    ?>
    </code>

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

    Пункт третий: Поиск сайтов
    Опять достал питон, и написал такое. Все очень просто, идем по файлу(построчно), переходим на странички пользователей, ищем сайты. Находим, прячем в файл.

    <code class="python">import urllib2, re
    
    sites = ""
    
    users = file("habrs2.txt")
    for user in users:
        user = re.split("\r\n", user)[0]
        page = urllib2.urlopen("http://habrahabr.ru/users/"+user+"/").read()
        site = re.findall('<a href="(.*?)" class="url icon" target="_blank">(.*?)</a>',page)
        if len(site) > 0:
            for site, fake in site:
                sites += site+"\r\n"
    
    
    with open("sites.txt", "a") as f:
        f.write(sites)
    </code>

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

    Пункт четвертый: Чистим сайты

    Используем preg_match в php.

    <code class="php"><?php
    $arr = file_get_contents("sites.txt");
    $arr = explode("\r\n", $arr);
    $string = "";
    foreach($arr as $name){
    	if (preg_match('/http:\/\/([^\/]+)\//i', $name, $matches)) {
    		$name = $matches[1];
    	} elseif (preg_match('/^http:\/\/([^\/]+)$/i', $name, $matches)) {
    		$name = $matches[1];
    	}
    	$string = $string.$name."\r\n";
    }
    file_put_contents("sites2.txt", $string);
    ?>
    </code>

    Получаем хороший список, аля:
    yandex.ru
    google.com
    yahoo.com

    Теперь нужно все это прикрутить к сканеру, получить ответ, спрятать в файл…

    Пункт пятый: полет со сканером

    На питоне была написана микропрограмма, для манипуляций с консолью.
    Пишу по памяти, потому как этот скрипт был написан на продакшне(BackTrack r3 на виртуалке), и после счастливого нахождения огромной кучи уязвимостей все это дело было закрыто, без сохранения(виртуалка в смысле), поэтому сам скрипт не сохранился…
    Смысл в том, чтобы запустить перл скрипт nikto.pl на 60 сек, и то, что он успеет за это время, записать в файл с именем сайта(для простоты дальнейшей обработки).
    <code class="python">import os, time
    
    sites = file("sites2.txt")
    for site in sites:
        os.system("perl nikto.pl -h "+site+" | tee "+site+".txt")
        os.system("pidof perl | tee perlID.txt")
        time.sleep(60)
        pid = file("perlID.txt")[0]
        os.system("taskkill "+pid)
    </code>

    После работы сего сканера в файлах вида: сайт.txt, обнаруживались быстро найденные уязвимости(в течение 60 секунд).

    Пункт шестой: разбор полетов

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

    Однако, среди 3-х сотен сайтов были обнаружены и «дырявые» сайты.

    Рейтинг уязвимостей

    1). Всевозможные открытые папки и не разрешенные к доступу файлы. (40~ сайтов)
    2). Различные возможные места SQL и XSS. (20~ сайтов)
    3). Опасные протоколы обмена информацией, незапароленные memcached и всяческие дыры в админках(нет проверки на доступ к файлам, или пустой пароль = полный пароль). (10~ сайтов)
    4). Откровенные ошибки(или недоработки). Отсутствие пароля на админку(скрипт ругался аж на 12 файлов, и посылал посмотреть, что же там интересного). (2 сайта)
    5). Встреченная в единственном экземпляре ошибка, и то по недосмотру(я думаю), прямой доступ к phpmyadmin'у с логином root и без пароля(дефолтные настройки). Больше на этом сайте НИКАКИХ уязвимостей найдено не было, поэтому считаю, что это просто по недосмотру.

    Проверены были не все пользователи, не все сайты, не все возможности из всех возможностей!

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

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Немножко анонимен

    Обсуждение анонимности нужно начинать не со слов прокси/тор/впн, а с определения задачи: анонимно подключиться к чужому серверу по SSH это одно, анонимно поднять свой веб-сайт это другое, анонимно работать в инете это третье, etc. — и все эти задачи решаются по-разному. Эта статья о задаче «анонимно работать в интернете как пользователь».

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

    Во-первых, нужно адекватно оценивать потенциального противника. Если вы хотите быть «анонимным», значит вы пытаетесь избежать возможности связывания вашей активности в интернете с вашим физическим расположением и/или настоящим именем. Обычные пользователи и так не имеют возможности вас отслеживать (технически, социальные методы когда по вашему нику на форуме легко гуглится ваш аккаунт в соц.сетях со всеми личными данными мы здесь не рассматриваем). Ваш провайдер/соседи могут иметь возможность прослушать большую часть вашего трафика, но, как правило, вы им не интересны (да, соседи могут украсть ваши пароли, но заниматься отслеживанием вашей активности или вашей деанонимизацией они не станут). Что же касается владельцев используемых вами ресурсов (веб-сайтов, прокси/vpn-серверов, etc.) то у них в распоряжении множество средств по отслеживаю вас (DNS-leaks, Flash/Java-плагины, баннерные сети, «отпечатки браузера», множество разных видов кук, etc.) плюс серьёзный коммерческий интерес к тому, чтобы надёжно вас отслеживать (для таргетирования рекламы, продажи данных, etc.). Ну а правительство и спец.службы могут получить доступ и к данным, которые на вас собирают веб-сайты, и к данным, которые собирают провайдеры. Таким образом получается, что те, кто имеют возможность и желание вас отслеживать — имеют доступ к большинству возможных каналов утечки.

    Во-вторых, каналов утечки информации очень и очень много. И они очень разнообразны (от внезапно отключившегося VPN до получения реального IP через Flash/Java-плагины браузера или отправки серийника на свой сервер каким-нить приложением при попытке обновления). Более того, регулярно обнаруживаются (и создаются) новые. Поэтому попытка блокировать каждый из них в индивидуальном порядке, уникальными для каждого методами, просто не имеет смысла, всё-равно что-то где-то протечёт.

    В-третьих, при «работе в интернете» используется не только браузер — большинство пользуются так же IM, торрентами, почтой, SSH, FTP, IRC… при этом часто информация передаваемая по этим каналам пересекается и позволяет их связать между собой (.torrent-файл скачанный с сайта под вашим аккаунтом грузится в torrent клиент, ссылка пришедшая в письме/IM/IRC открывается в браузере, etc.). Добавьте сюда то, что ваша ОС и приложения тоже регулярно лазят в инет по своим делам, передавая при этом кучу деанонимизирующей вас информации…

    Из всего этого логически следует то, что пытаться добавить «немножко анонимности» путём использования браузера со встроенным Tor, или настройкой торрент-клиента на работу через SOCKS — нет смысла. Большинство вас не сможет отследить и без этих мер, а тех, кто имеет возможности и желание вас отследить эти меры не остановят (максимум — немного усложнят/замедлят их работу).

    В общем случае есть только один способ обеспечить полноценную анонимность. Для некоторых частных задач могут существовать более простые решения — например, чтобы анонимно подключиться к серверу по SSH вроде бы достаточно использовать Tor. Но это исключения, к которым можно прибегать только если это редкие одноразовые задачи, да и тогда нужно быть достаточно внимательным, чтобы избежать, например, DNS-leaks. С учётом рисков, я бы не рекомендовал прибегать к таким решениям вообще — если иногда возникает потребность в анонимности, то надёжнее и проще один раз реализовать полноценный анонимный доступ к интернету и пользоваться только им. Поэтому гораздо полезнее описать (и помочь с установкой/настройкой) реализацию полноценной анонимности, чем описывать отличия между разными версиями протокола SOCKS или встраивать Tor в конкретный веб-браузер.

    Для начала нам потребуется виртуальная машина. У неё будет виртуальный сетевой интерфейс, работающий через NAT, т.е. с IP вроде 192.168.x.x и левым MAC. Таким образом, никакие Flash/Java-плагины, и или даже эксплойты взломавшие ваш браузер не смогут узнать ваш реальный IP.

    Далее, необходимо установить в эту виртуальную машину либо бесплатные ОС и все приложения (Linux), либо ворованные и взломанные (Windows) — чтобы при передаче в инет этими приложениями своих номеров лицензий их нельзя было связать с вами.

    Чтобы скрыть свой IP от посещаемых сайтов, и скрыть свой трафик от своего провайдера/соседей/Tor exit node вам потребуется доступ к VPN-сервису (не важно, на базе OpenVPN или SSH). Это должен быть либо бесплатный VPN, либо оплачиваемый через Bitcoin — но в любом случае не должно быть возможности связать (например, через кредитку использованную при оплате) вас с этим сервисом. (И, кстати, при оплате через биткоины тоже стоит быть осторожным.) ОС необходимо настроить так, чтобы весь трафик шёл только через VPN.

    Чтобы скрыть свой IP от владельцев VPN-сервиса и их провайдера — необходимо направить VPN-соединение через Tor.

    Чтобы гарантировать, что никакие сбои (или взлом с перенастройкой) внутри виртуальной машины не «засветят» ваш реальный IP адрес необходимо настроить файрвол на основной (host) системе так, чтобы весь (т.е. не только TCP, а действительно весь!) трафик виртуальной машины пропускался исключительно в Tor и никуда больше.

    Ну и последнее, но, тем не менее, очень важное: вы не должны вводить внутри этой виртуальной машины ничего такого, что может быть связано с вашей реальной личностью — имя, номера кредиток, заходить в «свои» аккаунты на любых сайтах, заливать (по крайней мере, без очистки EXIF-метаданных) на сайты фотки сделанные свои основным фотоаппаратом/телефоном, etc. Создайте отдельные «левые» аккаунты на всех нужных сайтах, заведите отдельные почтовые/IM-аккаунты (и не переписывайтесь между своими реальными и этими аккаунтами). Покупайте исключительно виртуальные товары (которые не нужно доставлять на ваш физический адрес) и только за биткоины.

    Вот и всё. Имея такую систему вы можете больше не беспокоиться о том, что вас будут отслеживать через разные виды кук, HTTP-заголовки и плагины, или случайно отвалится VPN-соединение. Т.е. отслеживать-то они будут, но физически к вам созданные ими профили привести не смогут. Ещё я бы рекомендовал в виртуальной системе использовать браузер и IM/email-клиенты визуально заметно отличающиеся от тех, которые в вашей основной системе — чтобы исключить нечаянное использование «не той» системы.

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

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Получение административных привилегий в Microsoft SQL Server

    Введение

    После смены рабочей станции начал ставить на нее Micorosft SQL Server 2008 R2 и чуть было не натолкнулся на традиционные грабли, связанные с улучшенной безопасностью в этой версии. Если в Microsoft SQL Server 2005 группа локальных администраторов по умолчанию включалась в роль sysadmin на SQL сервере, то в 2008-й в эту роль не включается никто:

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

    Описание процедуры

    В решении нет ничего неожиданного или революционного:
    1. Перезагрузить инстанс в однопользовательский режим (single user mode)
    2. Добавить нужного пользователя в администраторы сервера из-под любого пользователя из группы локальных администраторов
    3. Перезагрузить инстанс в нормальный режим

    Разжеванное описание процедуры

    Перегрузка в однопользовательский режим
    1. Запускаем оснастку конфигурации SQL сервером и останавливаем нужный инстанс (в моем случае — инстанс по умолчанию):
    2. Открываем свойства инстанса:
    3. Переключаемся на вкладку Advanced и прокручиваем свойства к параметру Startup Parameters:

    4. Добавляем параметр -m; (не забываем точку с запятой!). Этот параметр обозначает загрузку инстанса в однопользовательском режиме (single user mode). В этом режиме любой член группы локальных администраторов имеет привилегии системного администратора на инстансе. Также в этом режиме возможно единственное соединение с сервером, поэтому любые приложения, которые могут хотеть присоединиться к конфигурируемому инстансу, должны быть погашены. Полное описание параметров движка базы можно найти тут:

    5. Запускаем инстанс:

    Установка админских привилегий для пользователя
    Тут есть много способов, начиная от присоединения к серверу посредством SQL Server Management Studio и использования графической оснастки для добавления нужных прав и кончая использованием osql. Мы пойдем вторым путем. Запускаем cmd.exe под пользователем из группы локальных администаторов и выполняем сдедующую команду:
    osql -E -S .\InstanceName -Q "EXEC sp_addsrvrolemember 'DOM\User', 'sysadmin'", где InstanceName — имя инстанса, а DOM\User — это домен\пользователь, которому дается административный доступ к инстансу. В моем случае (с инстансом по умолчанию и для админского пользователя RU\venticello) выглядит это так:


    Запуск инстанса в обычном режиме
    Идем в обратном порядке:
    1. Останавливаем инстанс
    2. Удаляем параметр -m;
    3. Запускаем инстанс
    Вот, собственно и все!

    Автоматизация

    Хоть процедура и не архисложная и никоим образом не каждодневная, она, если честно, немного занудная и утомительная. Одно количество скриншотов является тому подтверждением. Я же являюсь убежденным апологетом утверждения, что все, что занудно, должно делаться компьютером, а не человеком — на то их и создавали. Поэтому я взял и описал все эти шаги в виде скрипта, предлагаемого вашему вниманию. Чтобы воспользоваться скриптом, его надо запустить из-под пользователя с административными привилегиями на машине с инстансом следующим образом:
    cscript /nologo acquire_admin_rights.js [<instance-name>]
    , где опциональный параметр instance-name обозначает инстанс, к которому надо предоставить админские права для запускающего пользователя. Если пропустить инстанс или задать имя MSSQLSERVER, доступ будет предоставлен к инстансу по умолчанию. Еще раз напоминаю, что надо удостовериться, что в течение процедуры нет никаких приложений, активно соединяющихся с этим инстансом, так как они могут перехватить единственное соединение, предоставляемое однопользовательским режимом.
    В процессе работы скрипт честно рассказывает о своих деяниях, поэтому, если что-то пойдет не так, можно понять, в чем причина и в каком состоянии оставлена система:


    Детали по скрипту

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

    WMI
    Вкратце, в контексте нашего повествования, WMI (Windows Management Instrumentation) — это сервис Windows, предоставляющий доступ к конфигурационной информации в унифицированном виде именованных классов, представленных набором свойств. Классы распиханы по пространствам имен (самое популярные из которых — это root\cimv2, в котором живет большинство классов, описывающих систему, и root\default, в котором живет класс реестра). На основании класса может существовать один или более экземпляров, обозначающих реальные описываемые объекты. Например, класс Win32_Service — это понятие службы, а каждый экземпляр — это набор свойств, соответствующий реальным службам, установленным на системе.

    Microsoft SQL Server в WMI
    Тут, как почти всегда с Microsoft, не обошлось от курчавости. Хоть сами SQL сервера обеспечивают обратную совместимость, что-то у них там не срослось на уровне конфигурации, так что абсолютно аналогичные классы конфигурации живут в двух разных пространствах имен:
    • root\Microsoft\SqlServer\ComputerManagement — для SQL Server 2005
    • root\Microsoft\SqlServer\ComputerManagement10 — для SQL Server 2008
    Соответственно, в общем случае искать наш инстанс надо в двух пространствах имен — ну а вдруг нашим скриптом захотят отконфигурировать пятый сервер?
    Итак, мы знаем пространство имен нужных классов, но как они называются, и как с ними работать? Тут нам на выручку приходит одна довольно корявая, но мощная утилитка — wbemtest.

    wbemtest
    wbemtest.exe — это стандартный клиент WMI (настолько стандартный, что присутствует в путях), поставляемый c WMI с первых дней появления этого сервиса аж в Windows 2000. Как следствие, интерфейс у этой утилиты суров, что, однако, не приумаляет его мощь. Выглядит он так:

    Пока мы не присоединимся к нужному пространству имен, делать нам в этой утилитке особо нечего. К счастью, мы знаем нужное пространство имен:
    root\Microsoft\SqlServer\ComputerManagement10:

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

    Ну все, теперь мы готовы копаться в пространстве имен в поисках нужных классов и свойств.

    Поиск нужных свойств
    Сначала смотрим, какие классы вообще существуют в этом пространстве имен. Для этого, очевидно, жмем на кнопку Enum Classes и в появившемся не совсем понятном диаложке нажимаем OK. В итоге появляется следующее окно:
    .
    Обычная женская интуиция подсказываем нам, что это, скорее всего, класс SqlServiceAdvancedProperty. Даблкликаем, открывая следующий диалог, показывающий свойства данного класса:

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

    Находим объект SqlServiceAdvancedProperty.PropertyIndex=13,SqlServiceType=1,PropertyName='STARTUPPARAMETERS',ServiceName='MSSQLSERVER'. Вот оно счастье!

    с WMI из скрипта
    Зная, какие классы и свойства нам нужны, остается только получить к ним доступ из скрипта. Рассматривать будем JScript, потому что распространяется со всеми Windows, да еще и JavaScript. Работа на VBScript или PowerShell ведется аналогично. Работа с WMI в скрипте начинается как и в случае wbemtest с подключения к нужному пространству имен. Делается это следующим кодом:
    <code class="javascript">function LookupInstanceContext(instance, scope) { try { var wmi = GetObject("WINMGMTS:\\\\.\\root\\Microsoft\\SqlServer\\" + scope); var settings = new Enumerator(wmi.ExecQuery("SELECT * FROM ServerSettings WHERE InstanceName='" + instance + "'")); if (!settings.atEnd()) { return wmi; } } catch (exception) {} return null; } </code>В качестве scope
    подается либо «ComputerManagement» либо «ComputerManagement10», в зависимости от того, какой версии SQL Server мы ищем. Примерно таким же кодом мы присоединяемся к пространству имен root\cimv2, посредством которого работаем со службами. Полученный объект wmi реализует интерфейс IWbemServices, но нас интересуют три следующих метода:
    • ExecQuery — выполнить запрос на языке WQL и вернуть список результатов
    • Get — получить конкретный экземпляр класса по идентификатору
    • ExecMethod — вызвать метод на объекте
    Чтобы потренироваться в умении делать WQL запросы и смотреть на результаты, нам поможет наш старый друг wbemtest нажатием кнопки Query... на основном окне. Вкратце, WQL (WMI Query Language) — это подмножество SQL в котором в качестве таблицы используется имя класса и выбирать конкретные колонки нельзя — только SELECT *. Например, чтобы найти все экземпляры инстанса сервера с именем MSSQLSERVER, можно написать следующий WQL запрос:

    Результат представлен в том же виде, в котором нам возвратились экземпляры класса (это и был результат запроса
    SELECT * FROM SqlServiceAdvancedProperty
    ).
    Для получения одного объекта по первичного ключу или полному набору свойств (для классов, у которых нет первичных ключей), используется метод
    Get. Вот функция, которая ответственна за получение строкового значения объекта SqlServiceAdvancedProperty
    по заданному пути:
    <code class="javascript">function GetPropertyValue(wmi, path) {
      return wmi.Get(path).PropertyStrValue;
    }
    </code>
    Изменение значения свойства подразумевает вызов метода
    SetStringValue (который указан в описании класса SqlServiceAdvancedProperty
    ). Чтобы его вызвать надо предварительно создать его аргумент, в который установить требуемое значение. Делается это следующей пачкой вызовов:
    <code class="javascript">function SetPropertyValue(wmi, path, value) {
      var arg = wmi.Get(path).Methods_("SetStringValue").inParameters.SpawnInstance_();
      arg.Properties_.Item("StrValue") = value;
      var result = wmi.ExecMethod(path, "SetStringValue", arg);
      if (result.ReturnValue != 0) {
        throw new Error("Failed to set property '" + path + "' to value '" + value + "'");
      }
    }
    </code>

    Заключение

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

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Загрузка файлов в AngularJS

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

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

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

    Загрузка каждого файла отдельным запросом. На любом хостинге существует ограничение на максимальный размер POST-запроса (напр., 10 МБ). Если мы грузим одновременно 10 файлов, значит их вес в сумме не должен превышать 10МБ. В 99% случаев проще пожертвовать производительностью и не иметь проблем с такими ограничениями.

    Никаких отложенных загрузок. Файл должен загружаться сразу после добавления (не в 2000 году, чай, живем), поэтому никаких методов работы с очередью — выбрал файл, выбрал еще 5 штук, удалил один, нажал «отправить» — не будет. Зато будет отмена загрузки.

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

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

    Особенности модуля
    • Загрузка файлов через xhr и iframe (для старых браузеров)
    • Чтение изображений до загрузки на сервер (если браузер поддерживает FileReader)
    • Одна директива для кнопки и области перетаскивания, как было сказано выше.
    • Встроенный валидатор, который при желании можно заменить своим.
    • Встроенная функция обработки ошибок, которую так же можно заменить своей.

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

    <code class="javascript">angular.module('myApp', ['oi.file']);
    </code>
    Использование директивы в HTML-шаблоне:

    <code class="html"><!-- Загрузка через проводник и перетаскиванием -->
    <input type="file" oi-file="options">
    
    <!-- Загрузка перетаскиванием на область -->
    <ul oi-file="options">
      <li ng-repeat="item in items">
        <img ng-src="{{item.thumb}}"> 
      </li>
    </ul>
    </code>
    Настройка в контроллере:

    <code class="javascript">$scope.file = {} //Модель
    $scope.options = {
      //Вызывается для каждого выбранного файла
      change: function (file) {
          //В file содержится информация о файле
          //Загружаем на сервер
          file.$upload('uploader.', $scope.file)
        })
      }
    }
    </code>
    Создание элемента модели для каждого файла:

    <code class="javascript">$scope.items = model;
    $scope.options = {
      change: function (file) {
        //Создаем пустой элемент для будущего файла
        $scope.add(function (i, id) {
    
          //Загружаем картинку через FileReader до загрузки на сервер
          file.$preview($scope.items[i]);
    
          //Загружаем на сервер
          file.$upload('uploader.php' + id, $scope.items[i], {allowedType: ["jpeg", "jpg", "png"]})
            .catch(function (data) {
              //Удаляем элемент при неудачной загрузке
              $scope.del(data.item.id);
            })
        })
      }
    }
    </code>
    Метод
    catch доступен, начиная с Ангуляра 1.2. В старых версиях используйте вместо него then(null, function (data) {...})
    .
    $preview
    и
    $upload
    возвращают обещания. См. $q.

    Пример с уменьшением изображения на клиенте:

    <code class="javascript">file.$preview({})
      .then(function (data) {
        //Изображение прочитано. Уменьшаем его с помощью canvas
        minimize(file._file);
        //Отправляем
        file.$upload('uploader.php', $scope.avatar)
    
      }, function (data) {
        //Изображение не прочитано. Отправляем как есть
        file.$upload('uploader.php', $scope.avatar)
      });
    </code>

    Исходники, демо
    Гитхаб, демонстрация, песочница

    Аналоги
    Параллельно nervgh написал angular-file-upload с гораздо более богатым АПИ, где на каждый чих формируется событие. Обратите внимание, кого не устроит бедность моего.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Из песочницы] Простая 4-х цветная многоканальная гирлянда на основе микроконтроллера ATTINY13A

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

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

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



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

    Как все устроено.



    Разработанная сеть способна адресовать до 254 подчиненных модулей, которые далее будут называться SLAVE — они соединены всего 3-мя проводами, как вы уже догадались — два провода это питание +12В, общий и третий — сигнальный.
    они имеют несложную схему:

    Как можно увидеть, она поддерживает 4 канала — Красный, Зеленый, Синий и Фиолетовый.
    Правда, по результатам практического тестирования, фиолетовый хорошо видно только вблизи но зато как! Так же, из-за того что цвета расположены слишком далеко друг от друга смешение цветов можно увидеть только метров с 10, если использовать RGB-светодиоды ситуация будет несколько получше.
    В целях упрощения конструкции так же пришлось отказаться и от кварцевой стабилизации — во-первых, лишний вывод забирает и во-вторых стоимость кварцевого резонатора довольно ощутима и в-третьих — в нем нет острой необходимости.
    На транзисторе собран защитный каскад, чтобы не выбило порт контроллера от статики — линия все же довольно длинной может быть, в крайнем случае пострадает только транзистор. Каскад рассчитан в MicroCap и имеет примерный порог срабатывания около 7 вольт и слабую зависимость порога от температуры.

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

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

    Схема:


    В схеме есть не обязательные потенциометры — их можно использовать в программе на ПК для удобной и оперативной настройки желаемых параметров, на данный момент это реализовано только в тестовой программе в виде возможности назначить любому из 4-х каналов любой из потенциометров. Схема подключается к ПК через преобразователь интерфейса USB-UART на микросхеме FT232.

    Пример выдаваемого пакета в сеть:


    Его начало:


    Электрические характеристики сигнала: лог.0 соответствует +9...12В, а лог.1 соответствует 0...5В.

    Как можно увидеть, данные передаются последовательно, с фиксированной скоростью по 4 бита. Это обусловлено необходимым запасом на ошибку по скорости приема данных — SLAVE-модули не имеют кварцевой стабилизации, а такой подход гарантирует прием данных при отклонении скорости передачи до +-5% сверх тех что компенсируются программным методом на основе измерения калиброванного интервала в начале передачи данных который дает стойкость к уходу опорной частоты еще на +-10%.

    Собственно, алгоритм работы MASTER-модуля не так интересен(он достаточно прост — получаем данные по UART и переправляем их в сеть подчиненных устройств), все самые интересные решения реализованы именно в SLAVE-модулях, которые собственно и позволяют подстраиваться под скорость передачи.

    Основным и самым главным алгоритмом является реализация 4-х канального 8-битного программного ШИМ который позволяет управлять 4-мя светодиодами при 256 градациях яркости каждого их них. Реализация этого алгоритма в железе так же определяет скорость передачи данных в сети — для программного удобства передается по одному биту на каждый шаг работы ШИМ. Предварительная реализация алгоритма показала что он выполняется за 44 такта, поэтому было принято решение использовать таймер настроенный на прерывание каждые 100 тактов — таким образом прерывание успевает гарантированно выполнится до наступления следующего и выполнить часть кода основной программы.
    На выбранной тактовой частоте внутреннего генератора в 4.8Мгц прерывания возникают с частотой 48кГц — именно такую битовую скорость имеет сеть подчиненных устройств и с такой же скоростью наполняется ШИМ — в итоге частота ШИМ-сигнала составляет 187.5Гц, чего вполне достаточно чтобы не замечать мерцания светодиодов. Так же, в обработчике прерывания после выполнения алгоритма ответственного за формирование ШИМ фиксируется состояние шины данных — получается примерно по середине интервала переполнения таймера, это упрощает прием данных. В начале приема очередного пакета в 4 бита происходит обнуление таймера, это необходимо для более точной синхронизации приема и стойкости к отклонению скорости приема.
    В итоге получается такая картина:


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

    <code>LDI    tmp2, st_syn_delay
    DEC    tmp2          ;<+
    BREQ   bad_sync      ; |
    SBIC   PINB, cmd_port; |
    RJMP   PC-0x0003     ;-+
    </code>

    st_syn_delay = 60 — константа, определяющая максимальную длительность стартового импульса, которая принята примерно в 2 раза больше номинала (для надежности)

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

    4.3Mhz (-10%) 51 единиц (0x33) соответствует 90 тактам таймера для возврата скорости приема к номиналу
    4.8Mhz (+00%) 43 единиц (0x2B) — соответствует 100 тактам таймера(номинал)
    5.3Mhz (+10%) 35 единиц (0x23) — соответствует 110 тактам таймера для возврата скорости приема к номиналу


    По этим данным были рассчитаны коэффициенты коррекции периода прерываний таймера(именно таким образом скорость приема подстраивается под имеющуюся тактовую частоту контроллера):

    Y(x) = 110-x*20/16
    x = tmp2 — 35 = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)
    Y(x) = (110, 108.75, 107.5, 106.25, 105, 103.75, 102.5, 101.25, 100, 98.75, 97.5, 96.25, 95, 93.75, 92.5, 91.25, 90)


    Числа округлены до целых и занесены в EEPROM.

    Если при подаче напряжения на модуль удерживать линию в логическом состоянии «1» включится подпрограмма калибровки, которая позволит измерить частотомером или осциллографом период ШИМ-сигнала без коррекции и на основании измерений судить об отклонении тактовой частоты контроллера модуля от номинальной, при сильном отклонении больше 15% может потребоваться коррекция калибровочной константы встроенного RC-генератора. Хотя производитель обещает калибровку на заводе и отклонение от номинала не более 10%.

    На данный момент, разработана программа на Delphi позволяющая воспроизводить ранее составленный паттерн для 8-ми модулей с заданной скоростью. А так же утилита для работы с отдельным модулем(в том числе переназначение адреса модуля).

    Прошивка.
    для SLAVE-модуля необходимо прошить только фьюзы CKSEL1 = 0, и SUT0 = 0. Остальные оставить непрошитыми. Содержимое EEPROM прошить из файла RGBU-slave.eep, при необходимости тут же можно задать желаемый адрес модуля в сети — 0-й байт EEPROM, по умолчанию прошит как $FE = 254, по адресу 0x13 содержится калибровочная константа встроенного RC-генератора контроллера, на частоте 4.8Мгц она не загружается автоматически поэтому необходимо программатором считать заводское значение калибровки и записать в эту ячейку — это значение индивидуально для каждого контроллера, при больших отклонениях частоты от номинала можно изменять калибровку именно через эту ячейку не затрагивая заводского значения.

    для MASTER-модуля необходимо прошить только фьюзы SUT0 = 0, BOOTSZ0 = 0, BOOTSZ1 = 0, CKOPT = 0. Остальные оставить непрошитыми.

    Напоследок небольшая демонстрация гирлянды расположенной на балконе:

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

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

    На данный момент доступны следующие команды:

    0x54; символ «T» — команда «test» — проверка соединения, ответ должен быть 0x2B.
    0x40; символ "@" — команда «загрузить и передать». После подачи команды нужно дождаться ответа "?" далее следует 6 байт данных:
    +0: Адрес подчиненного устройства 0..255
    +1: Команда устройству
    0x21 — байты 2...5 содержат яркость по каналам которую необходимо применить немедленно.
    0x14 — установить тайм-аут, по истечении которого яркость по всем каналам будет
    сброшена на 0 если за это время не поступит ни одной команды. Значение таймаута находится в ячейке красного канала, т.е. в байте со смещением +2. значение 0-255 соответствует таймауту в 0-25.5 сек по умолчанию, таймаут = 5 секунд(записан в EEPROM при прошивке, там же его можно и изменить в байте со смещением +1).
    0x5A — изменить адрес устройства.
    Процедура смены адреса для надежности должна быть выполнена троекратно — только тогда новый адрес будет применен и прописан в EEPROM. При этом надо быть осторожным -если прописать двум устройствам один адрес они будут реагировать синхронно а «разделить» их можно будет только физически отключив от сети лишние модули и сменив адрес у оставшегося, либо программатором. Значение нового адреса передается в ячейке красного канала — т.е. в байте со смещением +2.

    +2: Яркость красного 0...255
    +3: Яркость зеленого 0...255
    +4: Яркость синего 0...255
    +5: Яркость фиолетового 0...255

    0x3D; символ "=" — команда «АЦП». После подачи команды нужно дождаться ответа "?" далее следует передать 1 байт — номер канала АЦП 0..7 в двоичном виде(ASCII цифры 0..9 тоже подходят в этом качестве, поскольку старшие 4 бита игнорируются).
    В ответ команда возвращает 2 байта результата измерения в диапазоне 0...1023

    Возможные ответы на команды:
    0x3F; символ "?" — готовность к вводу данных, означает что устройство готово к приему аргументов команды
    0x2B; символ "+" Ответ — команда выполнена
    0x2D; символ "-" Ответ — команда не определена или ошибочна

    Больше подробностей можно выудить из исходников расположенных на гитхабе, там же лежат последние версии готовых прошивок: github.com/Alexeyslav/RGBU_light

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Из песочницы] Поиск подстроки. Алгоритм Кнута–Морриса-Пратта

    В задачах поиска информации одной из важнейших задач является поиск точно заданной подстроки в строке. Примитивный алгоритм поиска подстроки в строке основан на переборе всех подстрок, длина которых равна длине шаблона поиска, и посимвольном сравнении таких подстрок с шаблоном поиска. По традиции шаблон поиска или образец принято обозначать как needle (англ. «иголка»), а строку, в которой ведётся поиск — как haystack (англ. «стог сена»). На языке Python примитивный алгоритм выглядит так:

    <code class="python">index = -1
    for i in xrange(len(haystack)-len(needle)+1):
        success = True
        for j in xrange(len(needle)):
            if needle[j]<>haystack[i+j]:
                success = False
                break
        if success:
            index = i
            break
    print index
    </code>

    Обозначим n=|haystack|, m=|needle|. Простейший алгоритм поиска даже в лучшем случае проводит n–m+1 сравнений; если же есть много частичных совпадений, скорость снижается до O(n*m).

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

    Префикс-функция строки ?(S,i) – это длина наибольшего префикса строки S[1..i], который не совпадает с этой строкой и одновременно является ее суффиксом. Проще говоря, это длина наиболее длинного начала строки, являющегося также и ее концом. Для строки S удобно представлять префикс функцию в виде вектора длиной |S|-1. Можно рассматривать префикс-функцию длины |S|, положив ?(S,1)=0. Пример префикс функции для строки «abcdabcabcdabcdab»:

    S[i]abcdabcabcdabcdab
    ?(S,i)00001231234567456

    Предположим, что ?(S,i)=k. Отметим следующие свойства префикс-функции.
    1. Если S[i+1]=S[k+1], то ?(S,i+1)=k+1.
    2. S[1..?(S,k)] является суффиксом строки S[1..i]. Действительно, если строка S[1..i] оканчивается строкой S[1… ?(S,i)]=S[1..k], а строка S[1..k] оканчивается строкой S[1..?(S,k)], то и строка S[1..i] оканчивается строкой S[1..?(S,k)].
    3. ? j?(k,i), S[1..j] не является суффиксом строки S[1..i]. В противном случае было бы неверным предположение ?(S,i)=k, так как j>k.

    Рассмотренные свойства позволяют получить алгоритм алгоритм вычисления префикс-функции.
    Пусть ?(S,i)=k. Необходимо вычислить ?(S,i+1).
    1. Если S[i+1]=S[k+1], то ?(S,i+1)=k+1.
    2. Иначе, если k=0, то ?(S,i+1)=0.
    3. Иначе положить k:=?(S,i) и перейти к шагу 1.

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

    Алгоритм вычисления префикс-функции на языке Python:

    <code class="python">def prefix(s):
        v = [0]*len(s)
        i = 1
        for i in xrange(1,len(s)):
            k = v[i-1]
            while k > 0 and s[k] <> s[i]:
                k = v[k-1]
            if s[k] == s[i]:
                k = k + 1
            v[i] = k
        return v
    </code>

    Покажем, что время работы алгоритма составляет О(n), где n=|S|. Заметим, что асимптотику алгоритма определяет итоговое количество итераций цикла while. Это так, поскольку без учета цикла while каждая итерация цикла for выполняется за время, не превышающее константу. На каждой итерации цикла for k увеличивается не более чем на единицу, значит максимально возможное значение k=n–1. Поскольку внутри цикла while значение k лишь уменьшается, получается, что k не может суммарно уменьшиться больше, чем n–1 раз. Значит цикл while в итоге выполнится не более n раз, что дает итоговую оценку времени алгоритма O(n).

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

    Пусть S[0..m–1] – образец, T[0..n–1] – строка, в которой ведется поиск. Рассмотрим сравнение строк на позиции i, то есть образец S[0..m–1] сопоставляется с частью строки T[i..i+m–1]. Предположим, первое несовпадение произошло между символами S[j] и T[i+j], где i < j < m. Обозначим P = S[0..j–1] = T[i..i+j–1]. При сдвиге можно ожидать, что префикс S сойдется с каким-либо суффиксом строки P. Поскольку длина наиболее длинного префикса, являющегося одновременно суффиксом, есть префикс-функция от строки S для индекса j, приходим к следующему алгоритму:
    1. Построить префикс-функцию образца S, обозначим ее F.
    2. Положить k = 0, i = 0.
    3. Сравнить символы S[k] и T[i]. Если символы равны, увеличить k на 1. Если при этом k стало равно длине образца, то вхождение образца S в строку T найдено, индекс вхождения равен i – |S| + 1. Алгоритм завершается. Если символы не равны, используем префикс-функцию для оптимизации сдвигов. Пока k > 0, присвоим k = F[k–1] и перейдем в начало шага 3.
    4. Пока i < |T|, увеличиваем i на 1 и переходим в шаг 3.

    Возможная реализация алгоритма Кнута-Морриса-Пратта на языке Python выглядит так:

    <code class="python">def kmp(s,t):
        index = -1
        f = prefix(s)
        k = 0
        for i in xrange(len(t)):
            while k > 0 and s[k] <> t[i]:
                k = f[k-1]
            if s[k] == t[i]:
                k = k + 1
            if k == len(s):
                index = i - len(s) + 1
                break
        return index
    </code>

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Простая DWDM-система. Запуск на стенде

    На несколько дней к нам в офис приехала компактная DWDM-система Modultech MT-EW-2U и я успел её немножко погонять на стенде.
    Эта платформа выполнена по принципу «всё в одном»: в одном корпусе высотой 2U может быть полностью смонтирован DWDM-узел на 16 каналов до 10Гбит/с каждый. Возможна комплектация активными транспондерами с коррекцией ошибок или использование «цветных» сигналов от DWDM-трансиверов.
    В нашей конфигурации использовалась упрощенная комплектация без транспондеров и с внешними компенсаторами дисперсии волоконного типа, хотя платформа позволяет использовать встроенные компактные компенсаторы на основе решеток Брэгга.
    image
    Платформа MT-EW в двухъюнитовом исполнении может использоваться как для оконечного узла, так и для транзитного.
    Конструктивно платформа состоит из двух независимых оптических подсистем на восемь каналов каждая; режим работы определяется выбором комплектующих модулей и схемой коммутации.
    В нашем тесте мы запустим девять каналов 10Гбит/с через двухволоконную трассу длиной 120км. Качество связи проверим bit-error rate тестером (BERT).
    Описание общих условий.
    Для трассы 120км будет использоваться следующая схема:
    image
    В качестве оконечного оборудования будет использован коммутатор Ethernet Eltex MES-3124F с 24 портами SFP 1GbE и четырьмя портами SFP+ 10GbE, укомплектованный оптическими трансиверами DWDM SFP+ на 80км Modultech MT-DP-xx192-08CD.
    Требования к оптическим сигналам в такой системе будут определяться характеристиками оптических трансиверов и условиями минимизации нелинейных эффектов в оптическом волокне. Их краткая сводка приведена в таблице:







    Условие
    Критерий
    Уровень выходного сигнала оптического трансивера
    От 0 до +5дБм, не регулируется.
    Уровень сигнала на входе оптического трансивера
    От -20 до -8дБм.
    Уровень сигнала в одном DWDM-канале после усилителя мощности
    Не более +8дБм
    Соотношение сигнал/шум на входе оптического трансивера
    Лучше, чем 25дБ
    Общая мощность группового сигнала после усилителя мощности
    Не более +17дБм
    При настройке многоканальной системы следует учитывать следующие факторы:
    — Затухание сигнала на оптическом мультиплексоре (участок оптического тракта от выхода с трансивера до входа в усилитель мощности) может составлять до 7дБ и сильно зависит от чистоты оптических соединений
    — Коэффициент усиления усилителя мощности регулируется в диапазоне 12-17дБ, предусилителя — в диапазоне 20-30дБ.
    — Для повышения соотношения сигнал/шум желательно запускать в трассу максимально возможный уровень сигнала в одном DWDM-канале При этом следует придерживаться ограничения в +8дБм/канал, иначе высока вероятность получения нелинейных искажений сигнала. При необходимости уменьшения уровня сигнала на входе в линию следует применять аттенюатор.
    — Регулировками на приемной стороне соотношение сигнал/шум улучшается крайне незначительно, по сравнению с регулировками на передающей стороне.
    — Оптические усилители имеют режим насыщения на уровне около +17дБм суммарной мощности выходного группового сигнала. Это влияет на уровни сигнала в одном DWDM-канале при увеличении числа одновременно передающихся каналов. Фактически в режиме насыщения усилителя коэффициент усиления зависит от количества передаваемых каналов и меньше номинально установленного.
    Монтаж стенда
    Для проверки системы смонтируем тестовый стенд:
    image
    В тесте будут использованы следующие компоненты:












    Наименование
    Количество
    Шасси компактной DWDM-платформы MT-EW-2U с двумя блоками питания 220В переменного тока
    2
    Модуль восьмиканального двухволоконного оптического мультиплексора DWDM для компактной платформыMT-EW-D8
     
    2
    Модуль оптического усилителя мощности (booster EDFA) для компактной платформы MT-EW-OAB17
    2
    Модуль оптического предусилителя (pre-EDFA) для компактной платформы MT-EW-OAP17
    2
    Модуль оптического клиентского адаптера для компактной платформы MT-EW-MOA
    8
    Компенсатор дисперсии 60км, MT-DCM-60
    2
    Оптический DWDM-трансивер 10G SFP+ Modultech MT-DP-xx192-08CD, каналы 20-28
    18
    Оптоволокно G.652 в катушках по 20км
    12
    Измеритель оптической мощности
    1
    Оптический спектроанализатор DWDM-диапазона
    1
    Сборка системы не вызывает лишних вопросов. Все оптические порты DWDM-системы оконцованы в розетки типа LC/UPC, компенсаторы дисперсии имеют порты типа SC/UPC. Основная часть монтажа выполняется дуплексными патчкордами, оптимальная длина — 30см. Маркировка «TX», «RX», «IN», OUT" на платформе обозначает направление передачи сигнала относительно самой системы: через порты «RX» или «IN» оптический сигнал входит в платформу, через порты «TX» или «OUT» оптический сигнал выходит из платформы.
    Оптические соединения для групповых сигналов выполняются согласно следующей таблице:









    Откуда
    Куда
    Примечание
    MUX/DMUX OUT
    Booster EDFA IN
    Общий выход мультиплексора подключается к входу усилителя мощности
    Booster EDFA OUT
    Вход в линию
     
    MUX/DMUX OSC OUT
    Booster EDFA OSC
    Выход оптического сервисного канала
    Выход из линии
    Pre-EDFA IN
     
    Pre-EDFA OUT
    DCM IN
    Усиленный сигнал на приеме передается на компенсатор дисперсии
    Pre-EDFA OSC
    MUX/DMUX OSC IN
    Вход оптического сервисного канала
    DCM OUT
    MUX/DMUX IN
    Сигнал после компенсатора дисперсии передается на демультиплексор
    Каналы передачи данных подключаются к сервисным картам ввода-вывода. В данной конфигурации использованы простые оптических адаптеров, которые представляют собой просто выводы оптических каналов мультиплексора для подключения внешних «цветных» сигналов.
    Каждый мультиплексор в платформе обслуживает до восьми каналов, попарно выведенных на разъемы сервисных карт, каждая сервисная карта обслуживает до двух клиентских каналов связи. При необходимости подключения большего количества каналов мультиплексоры каскадируются через выделенные upgrade-порты.
    Распределение частот (длин волн) отдельных каналов связи по слотам сервисных карт статическое и полностью определяется оптической схемой установленного мультиплексора.
    Подключение клиентских каналов лучше проводить в два этапа: сначала подключить передающие порты, выровнять уровни оптических сигналов согласно описанным в первом разделе критериям и только после этого подключать приемные порты трансиверов. Такая последовательность обезопасит оптические приемники от перегрузки и облегчит настройку системы.
    После подключения передатчиков необходимо с помощью спектроанализатора проверить равномерность уровней в групповом сигнале и соответствие их общим условиям. При первоначальном монтаже спектроанализатор подключается напрямую к линии, общему выходу мультиплексора или усилителя. При настройке работающей системы необходимо пользоваться портами мониторинга («TAP») оптических усилителей.
    В представленной системе сигнал в порт мониторинга передается с ослаблением на 13.6дБ (5%).
    В нашем случае на общем выходе мультиплексора получилась такая спектрограмма:
    image
    Рекомендуется сохранять в архивах спектрограммы, полученные в контрольных точках системы как при запуске системы в эксплуатацию, так и при изменении конфигурации (добавлении, исключении каналов, расширении системы и т.п.).

    Настройка и проверка системы

    После того, как все необходимые соединения выполнены и проведена базовая настройка оптического тракта, необходимо проверить качество передачи трафика.
    Для этого лучше всего использовать специальные BER-тестеры, позволяющие быстро оценить надежность передачи простых битовых последовательностей.
    Настройку системы лучше всего начинать с конфигурации, в которой все усилители отрегулированы на минимально возможные уровни усиления и имеется запас в несколько децибел до насыщения усилителей. При необходимости такой запас можно сделать, включив аттенюатор между выходом мультиплексора и входом усилителя мощности.
    Последовательно подключая битовый тестер к разным каналам, нужно убедиться в отсутствии ошибок передачи.
    При выявление ошибок на отдельном канале нужно:
    — проверить уровни сигналов и оптический спектр на оптических приемниках. К ошибкам может приводить как слишком слабый, так и слишком сильный сигнал на фотоприемнике. Соотношение сигнал/шум должно быть лучше 25дБ.
    — очистить оптические розетки и коннекторы передатчиков и приемников сбойного канала.
    При выявлении слишком слабого сигнала на входе оптического приемника и отсутствия результата после чистки соединений следует прибегнуть к регулировкам оптического усиления. При этом следует иметь в виду, что регулировки усилителей влияют сразу на все оптические каналы, после регулировки необходимо проверить работоспособность других каналов связи.
    Если ошибки выявляются на большинстве включенных каналов, следует обратить внимание на возможные нелинейные эффекты в оптоволокне и достаточность соотношения сигнал/шум в каналах. Надо помнить, что регулировка на передающей стороне более эффективна, чем на приемной.
    Одной из возможных причин неустойчивой связи для 10Гбит/с линий является нескомпенсированная хроматическая дисперсия. В рассматриваемой конфигурации используются компенсаторы дисперсии на 60км стандартного волокна G.652 и трансиверы с устойчивостью до 80км, таким образом при длине линии в 120км на входе трансиверов уровень нескомпенсированной дисперсии будет порядка 60км. Несмотря на достаточный запас в 20км, дисперсия может приводить к неустойчивой связи. В этом случае рекомендуется включить компенсатор дисперсии с большим номиналом.
    Итоги.
    При настройке данной системы и включении девяти одновременных каналов положительный результат (то есть отсутствие ошибок на всех каналах) был достигнут после исключения аттенюаторов и минимальных значениях усиления в настройках:
    <code class="dos">192.168.0.179:> sh int 1/15/1 edfa
        <Interface EDFA 1/15/1> 
                     Admin : Enable                                  
                Alias Name : 
                      Gain :   12.0                                  
    
            Service Status : IS                                      
                     Alarm : NoDetect                                
    
                InputPower :    6.5 dBm                              
               OutputPower :   18.6 dBm                              
         ModuleTemperature :   31.7 C                                
                 OpCurrent :  352.1 mA                               
                   OpPower :  214.2 mW                               
           ChipTemperature :   25.0 C                                
            CoolingCurrent :  115.5 mA                               
    
             Serial Number : 990647                                  
                      Type : BA                                      
    
                  
    192.168.0.179:> sh int 1/16/1 edfa
        <Interface EDFA 1/16/1> 
                     Admin : Enable                                  
                Alias Name : 
                      Gain :   20.0                                  
    
            Service Status : IS                                      
                     Alarm : NoDetect                                
    
                InputPower :   -4.8 dBm                              
               OutputPower :   15.2 dBm                              
         ModuleTemperature :   29.0 C                                
                 OpCurrent :  162.1 mA                               
                   OpPower :  109.3 mW                               
           ChipTemperature :   25.0 C                                
            CoolingCurrent :   58.0 mA                               
    
             Serial Number : 990651                                  
                      Type : PA                                      
    </code>
    Как следует из отчета о состоянии усилителя мощности, он работает в режиме насыщения (выходная мощность — +18дБм), что приведет к уменьшению уровней сигнала в каждом канале при включении дополнительных каналов. Это не должно привести к деградации сервиса, так как уровень сигналов на выходе из системы составляет около -9дБм во всех каналах, что с большим запасом перекрывает чувствительность SFP+-модуля.
    При эксплуатации системы необходимо непрерывно отслеживать с помощью систем мониторинга качество передачи сигнала (наличие и количество ошибок на трансиверах) совместно с уровнями оптического сигнала на усилителях и трансиверах. Результаты такого мониторинга существенно облегчит решение инцидентов, отслеживание качества предоставляемого сервиса и дальнейшее расширение системы.
    Описание системы управления и мониторинга — тема отдельной статьи, за которой — надеюсь — дело не встанет.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Из песочницы] Взлет и падение начинающего фрикера

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

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

    Итак, дело было в 1997-м году, когда я был студентом второго курса питерской «Корабелки» (СПбГМТУ). В Петербург я понаехал в сознательном уже возрасте 21 года из Калининградской области, где прожил всю жизнь до этого. Понаехал я уже с мощным ИТ-бекграундом, т.к. фанатично занимался программированием примерно с 13 лет (чтоб вы представляли масштаб фанатизма — я написал две игры и графический редактор для УКНЦ прямо в восьмеричных машинных кодах, используя только процессорный отладчик).

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

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

    image

    Принимали эти таксофоны чип- стандарта ISO-7816-2 емкостью от 25 до 1000 единиц (одна единица — минута местного разговора или несколько секунд междугородного). Собрав всю имеющуюся на тот момент в FIDO и в дефицитном интернете информацию о видах и протоколах карт, мы принялись за работу. Довольно скоро мы собрали ридер, подключающийся к LPT порту компьютера. Была также написана программа, читающая содержимое карт. Карта представляет собой память небольшого объема, одна часть которой содержит информацию об оставшихся единицах и может быть изменена (только в сторону уменьшения), вторая часть содержит служебную информацию: производитель, серийный номер, что-то еще.

    Накопив достаточное количество знаний о протоколе обмена таксофона с карточкой и собрав небольшую коллекцию дампов карт, мы приступили к выполнению программы-максимум, то есть к созданию эмулятора карты, который бы вел себя как обычная карта, но область единиц была бы доступна на запись любых чисел. В качестве мозга эмулятора был выбран микроконтроллер PIC16F84a, программа его писалась на С в среде Borland C 3.0. Я занимался софтовой частью, то есть писал программу для микроконтроллера и служебные программы для компьютера, Кирилл был властелином микроконтроллера и монстром паяльника.

    Процесс построения и отладки первой версии эмулятора был сущим адом. В железном плане первая версия была весьма неказистой и представляла собой карточку с выфрезерованными родными мозгами, из которой торчал жгут проводов, на котором висела плата с контроллером и обвязкой. К плате синей, конечно же, изолентой была прикручена квадратная батарейка. Мало того, из-за отсутствия полной информации мы многое делали наугад (тайминги протокола приходилось подбирать методом проб и ошибок), так еще и представьте себе процесс проверки очередной сборки прошивки: «так, мы поменяли здесь число 10 на 12, пойдем пройдемся пару километров по морозу до ближайшего таксофона, подождем, пока вокруг не будет любопытных граждан, воткнем девайс в таксофон, увидим в сотый раз надпись „Ошибка 8“, тихо выругаемся и пойдем обратно». А теперь представьте себе нашу радость, когда на сто первый раз эмулятор частично заработал и таксофон показал долгожданное «25 единиц». Этот этап занял у нас примерно полгода.

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

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

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

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

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

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    EmBlocks — IDE для STM32

    Я обещал поделиться своей настроенной средой Em::Blocks.
    Выполняю обещание.


    Что такое Em::Blocks?

    Это IDE на основе Code::Blocks — кросс-платформенной быстрой среды разработки со встроенным скриптовым языком и очень гибкой настройкой, ориентированной под С/С++ разработку. В среде есть встроенные шаблоны для кучи различных случаев и возможность подключать любые компиляторы.
    EmBlocks в отличие от CodeBlocks не кросс-платформенная, она существует только под Windows.
    Зато вместе с ней поставляется специальная версия CodeSourcery тулчейна, которая позволяет плотнее интегрировать тулчейн с IDE. Версия в комплекте всегда свежая.
    Достоинства EmBlocks
    • быстрая, т.к. написана в native коде
    • расширяемая и хорошо автоматизируется с помощью скриптов
    • шаблоны проектов можно настроить на свой вкус
    • можно самому изменить диалог мастера создания проекта
    • не требует установки — можно носить с собой на флешке и легко перенести с настройками на другой комп
    • из коробки поддерживает отладку через ST-Link и J-Link
    • бесплатная
    • неплохо поддерживается на собственном форуме

    Я работаю чаще всего с STM32F103C8, STM32F103VE, STM32F100RB, поэтому и шаблоны проектом модифицировал под них. Но адаптировать под другие процессоры никакой сложности не составляет. Если будут конкретные вопросы — напишу как.
    Я настроил ее под себя:
    • Отредактировал шаблоны проектов под STM32F10x medium density, high density, medium density value line
    • В шаблонах заменил структуру проекта разложив по папкам stm_lib, cmsis, cmsis_boot и Src.
    • Обновил версию cmsis в шаблоне проекта до версии 3.0
    • Добавил поддержку ColinkEx debugger (она не очень гибкая, но работает)
    • Добавил выбор процессора в мастере создания проекта для прошивки с помощью ColinkEx
    • Добавил в меню Tools пункты »Flash w ColinkEx», «Flash w ST-Link/V2?
    • Изменил настройку по-умолчанию для ST-Link отладчика с JTAG на SWD
    • Добавил создание HEX файла для Debug target (стандартно только для Release)
    • Добавил в build options USE_STDPERIPH_DRIVER
    • Добавил в search directories stm_lib\src, stm_lib\inc, .\STM32_USB-FS-Device_Driver\src, .\STM32_USB-FS-Device_Driver\inc, cmsis, cmsis\boot
    • Исправил в gcc_arm.ld размер флеша и памяти для STM32F10x_MD серии на значения для STM32F103C8
    Что-то менял еще по мелочам, но уже не помню.
    Для того, чтобы начать работать с EmBlocks достаточно распаковать архив и запустить emblocks.exe.
    Если кому не нравятся внесенные мной изменения — оригинал лежит на сайте разработчиков. Оригинальный splashscreen тоже лежит внутри архива.

    Что дают изменения:

    • Проект готов к прошивке сразу после создания визардом
    • Есть все, что нужно, для того, чтобы поморгать светодиодом
    • Проект рассчитан на использование STM32 StdPeriph Library (по мере необходимости добавляем модули к проекту в папку stm_lib, архив в конце статьи)
    • Для работы с USB-FS библиотекой нужно всего лишь кинуть ее в каталог проекта и добавить в проект. (архив с библиотекой в конце статьи)
    • Свежий компилер не ругается на оптимизацию благодаря новой версии CMSIS
    • Легко перенести проект из CooCox IDE
    • Можно использовать CoolinkEx, который довольно популярен у нас и можно купить в России
    Наверняка у каждого из нас есть свои тонкости в разработке, поэтому охватить все их я не смогу. Я собираюсь рассказать как пользоваться всем этим в следующих записях. Задавайте вопросы, я постараюсь их учесть при описании.
    Вообще у меня есть мысль снизить порог входа в разработку под STM32, облегчив старт набором удобных инструментов. Поставил и через 2 минуты у тебя работает Blink.
    Архив EmBlocks и библиотеки: STM32F10x StdPeriph Library, STM32 USB-FS-Device driver я выложил у себя на сайте.
    Просьба — не положите хостинг :) Если не собираетесь пользоваться прямо сейчас — скачайте потом.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Из песочницы] Воспроизведение звука в Java

    Воспроизведение звука в Java

    Введение
    Нормальной русскоязычной информации по теме просто нет. Java-tutorials тоже оставляют желать лучшего. А архитектура javax.sound.sampled хоть и проста, но далеко не тривиальна (я бы вообще сказал, что этот пакет писали извращенцы). Поэтому свой первый пост на Хабре я решил посвятить именно этой теме. Приступим:

    Воспроизведение звука
    Тут всё более-менее просто. Импортируем javax.sound.sampled и поехали:
    <code class="java">try {
    	File soundFile = new File("snd.wav"); //Звуковой файл
    	
    	//Получаем AudioInputStream
    	//Вот тут могут полететь IOException и UnsupportedAudioFileException
    	AudioInputStream ais = AudioSystem.getAudioInputStream(soundFile);
    	
    	//Получаем реализацию интерфейса Clip
    	//Может выкинуть LineUnavailableException
    	Clip clip = AudioSystem.getClip();
    	
    	//Загружаем наш звуковой поток в Clip
    	//Может выкинуть IOException и LineUnavailableException
    	clip.open(ais);
    	
    	clip.setFramePosition(0); //устанавливаем указатель на старт
    	clip.start(); //Поехали!!!
    
    	//Если не запущено других потоков, то стоит подождать, пока клип не закончится
            //В GUI-приложениях следующие 3 строчки не понадобятся
    	Thread.sleep(clip.getMicrosecondLength()/1000);
    	clip.stop(); //Останавливаем
    	clip.close(); //Закрываем
    } catch(IOException | UnsupportedAudioFileException | LineUnavailableException exc) {
    	exc.printStackTrace();
    } catch (InterruptedException exc) {}
    </code>

    Регулятор громкости
    Поигравшись со звуками вы наверняка захотите иметь возможность программно изменять громкость звука. Java Sound API предоставляет такую возможность с фирменной кривотой.
    <code class="java">//Получаем контроллер громкости
    FloatControl vc = (FloatControl)clip.getControl(FloatControl.Type.MASTER_GAIN);
    //Устанавливаем значение
    //Оно должно быть в пределах от vc.getMinimum() до vc.getMaximum()
    vc.setValue(5); //Громче обычного
    </code>
    Этот код нужно поместить между строчками clip.open(ais) и clip.setFramePosition(0).

    Упрощаем процесс
    Ну и наконец, чтобы вы не мучились, выкладываю класс для проигрывания звуков
    <code class="java">import java.io.File;
    import java.io.IOException;
    
    import javax.sound.sampled.AudioInputStream;
    import javax.sound.sampled.AudioSystem;
    import javax.sound.sampled.Clip;
    import javax.sound.sampled.FloatControl;
    import javax.sound.sampled.LineEvent;
    import javax.sound.sampled.LineListener;
    import javax.sound.sampled.LineUnavailableException;
    import javax.sound.sampled.UnsupportedAudioFileException;
    
    public class Sound {
    	private boolean released = false;
    	private Clip clip = null;
    	private FloatControl volumeC = null;
    	private boolean playing = false;
    	
    	public Sound(File f) {
    		try {
    			AudioInputStream stream = AudioSystem.getAudioInputStream(f);
    			clip = AudioSystem.getClip();
    			clip.open(stream);
    			clip.addLineListener(new Listener());
    			volumeC = (FloatControl)clip.getControl(FloatControl.Type.MASTER_GAIN);
    			released = true;
    		} catch(IOException | UnsupportedAudioFileException | LineUnavailableException exc) {
    			exc.printStackTrace();
    			released = false;
    		}
    	}
    
    	//true если звук успешно загружен, false если произошла ошибка
    	public boolean isReleased() {
    		return released;
    	}
    	
    	//проигрывается ли звук в данный момент
    	public boolean isPlaying() {
    		return playing;
    	}
    
    	//Запуск
    	/*
    	  breakOld определяет поведение, если звук уже играется
    	  Если reakOld==true, о звук будет прерван и запущен заново
    	  Иначе ничего не произойдёт
    	*/
    	public void play(boolean breakOld) {
    		if (released) {
    			if (breakOld) {
    				clip.stop();
    				clip.setFramePosition(0);
    				clip.start();
    				playing = true;
    			} else if (!isPlaying()) {
    				clip.setFramePosition(0);
    				clip.start();
    				playing = true;
    			}
    		}
    	}
    	
    	//То же самое, что и play(true)
    	public void play() {
    		play(true);
    	}
    	
    	//Останавливает воспроизведение
    	public void stop() {
    		if (playing) {
    			clip.stop();
    		}
    	}
    
    	//Установка громкости
    	/*
    	  x долже быть в пределах от 0 до 1 (от самого тихого к самому громкому)
    	*/
    	public void setVolume(float x) {
    		if (x<0) x = 0;
    		if (x>1) x = 1;
    		float min = volumeC.getMinimum();
    		float max = volumeC.getMaximum();
    		volumeC.setValue((max-min)*x+min);
    	}
    	
    	//Возвращает текущую громкость (число от 0 до 1)
    	public float getVolume() {
    		float v = volumeC.getValue();
    		float min = volumeC.getMinimum();
    		float max = volumeC.getMaximum();
    		return (v-min)/(max-min);
    	}
    
    	//Дожидается окончания проигрывания звука
    	public void join() {
    		if (!released) return;
    		synchronized(clip) {
    			try {
    				while (playing) clip.wait();
    			} catch (InterruptedException exc) {}
    		}
    	}
    	
    	//Статический метод, для удобства
    	public static Sound playSound(String s) {
    		File f = new File(s);
    		Sound snd = new Sound(f);
    		snd.play();
    		return snd;
    	}
    
    	private class Listener implements LineListener {
    		public void update(LineEvent ev) {
    			if (ev.getType() == LineEvent.Type.STOP) {
    				playing = false;
    				synchronized(clip) {
    					clip.notify();
    				}
    			}
    		}
    	}
    }
    </code>

    Пользоваться очень просто, например:
    <code class="java">Sound.playSound("sounds/hello.wav").join();
    </code>

    Форматы
    Пару слов о поддержке форматов звуковых файлов: забудьте про mp3 и вспомните wav. Также поддерживаются au и aif.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Pro Core Data for iOS. Глава №1. Практическая часть

    Хабралюди, добрый день!
    Сегодня хочу начать вольный перевод книги Михаеля Привата и Роберта Варнера «Pro Core Data for iOS», которую можете скачать по этой ссылке. Каждая глава будет содержать теоретическую и практическую часть.

    image

    Содержание:
    • Глава №1. Приступаем (Практическая часть)
    • Глава №2. Усваиваем Core Data
    • Глава №3. Хранение данных: SQLite и другие варианты
    • Глава №4. Создание модели данных
    • Глава №5. Работаем с объектами данных
    • Глава №6. Обработка результатирующих множеств
    • Глава №7. Настройка производительности и используемой памяти
    • Глава №8. Управление версиями и миграции
    • Глава №9. Управление таблицами с использованием NSFetchedResultsController
    • Глава №10. Использование Core Data в продвинутых приложениях



    Практическая часть

    Так как это первая глава и её можно считать вводной, то в качестве практического задания мы выберем создание обычного социального приложения, которое будет отображать список наших друзей из ВК и использовать Core Data для хранения данных о них.
    Примерно (в процессе решим что добавить/исключить) таким образом будет выглядеть наше приложение после нескольких часов (а может и минут) упорного программирования:
    image
    image

    Как Вы могли уже догадаться, использовать мы будем Vkontakte iOS SDK v2.0.
    Кстати, прошу меня простить за то, что в практической части будет использоваться не только XCode, но и AppCode (ребятам из JB спасибо за продукт!). Всё, что можно сделать в AppCode, будет там сделано.

    Поехали…

    Создание пустого проекта
    Создадим пустой проект без Core Data — Single View Application.
    image
    image

    Приложение удачно запустилось:
    image

    Добавление и настройка UITableView
    Открываем ASAViewController.h и добавляем следующее свойство:
    <code class="objectivec">@property (nonatomic, strong) UITableView *tableView;
    </code>
    Полный вид ASAViewController.h:
    <code class="objectivec">#import <UIKit/UIKit.h>
    
    @interface ASAViewController : UIViewController
    
    @property (nonatomic, strong) UITableView *tableView;
    
    @end
    </code>
    Открываем ASAViewController.m и в метод viewDidLoad добавляем строки создания таблицы UITableView:
    <code class="objectivec">    CGRect frame = [[UIScreen mainScreen] bounds];
        _tableView = [[UITableView alloc]
                                   initWithFrame:frame
                                           style:UITableViewStylePlain];
        [self.view addSubview:_tableView];
    </code>
    Полный вид ASAViewController.m:
    <code class="objectivec">#import "ASAViewController.h"
    
    @implementation ASAViewController
    
    - (void)viewDidLoad
    {
        CGRect frame = [[UIScreen mainScreen] bounds];
        _tableView = [[UITableView alloc]
                                   initWithFrame:frame
                                           style:UITableViewStylePlain];
        [_tableView setDelegate:self];
        [_tableView setDataSource:self];
        [self.view addSubview:_tableView];
    }
    
    @end
    </code>

    Запускаем:
    image

    Осталось реализовать методы делегатов UITableViewDelegate и UITableViewDataSource.
    Дописываем протоколы в  ASAViewController.h:
    <code class="objectivec">@interface ASAViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
    </code>
    Открываем ASAViewController.m и реализовываем два метода (один для возврата кол-ва друзей в списке, а второй для создания заполненной ячейки с данными пользователя):
    <code class="objectivec">#pragma mark - UITableViewDelegate & UITableViewDataSource
    
    - (NSInteger)tableView:(UITableView *)tableView
      numberOfRowsInSection:(NSInteger)section
    {
        return [_userFriends count];
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView
      cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *cellID = @"friendID";
    
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
        if(nil == cell){
            cell = [[UITableViewCell alloc]
                    initWithStyle:UITableViewCellStyleSubtitle
                  reuseIdentifier:cellID];
        }
    
        //    setting default image while main photo is loading
        cell.imageView.image = [UIImage imageNamed:@"default.png"];
    
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
            NSString* imgPath = _userFriends[(NSUInteger)indexPath.row][@"photo"];
            NSData* img = [NSData dataWithContentsOfURL:[NSURL URLWithString:imgPath]];
    
            dispatch_async(dispatch_get_main_queue(), ^{
                cell.imageView.image = [UIImage imageWithData:img];
            });
        });
    
        NSString* firstName = _userFriends[(NSUInteger)indexPath.row][@"first_name"];
        NSString* lastName = _userFriends[(NSUInteger)indexPath.row][@"last_name"];
        NSString* fullName = [NSString stringWithFormat:@"%@ %@", firstName, lastName];
        cell.textLabel.text = fullName;
    
        NSString* status = _userFriends[(NSUInteger)indexPath.row][@"status"];
        cell.detailTextLabel.text = status;
    
        return cell;
    }
    </code>

    Переменная _userFriends является свойством ASAViewController:
    <code class="objectivec">@property (nonatomic, strong) NSMutableArray *userFriends;
    </code>

    Итоговый вид ASAViewController.h и ASAViewController.m:
    <code class="objectivec">#import <UIKit/UIKit.h>
    
    @interface ASAViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
    
    @property (nonatomic, strong) UITableView *tableView;
    @property (nonatomic, strong) NSMutableArray *userFriends;
    
    @end
    </code>
    <code class="objectivec">#import "ASAViewController.h"
    
    @implementation ASAViewController
    
    - (void)viewDidLoad
    {
        _userFriends = [[NSMutableArray alloc] init];
    
        CGRect frame = [[UIScreen mainScreen] bounds];
        _tableView = [[UITableView alloc]
                                   initWithFrame:frame
                                           style:UITableViewStylePlain];
        [_tableView setDelegate:self];
        [_tableView setDataSource:self];
        [self.view addSubview:_tableView];
    }
    
    #pragma mark - UITableViewDelegate & UITableViewDataSource
    
    - (NSInteger)tableView:(UITableView *)tableView
      numberOfRowsInSection:(NSInteger)section
    {
        return [_userFriends count];
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView
      cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *cellID = @"friendID";
    
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
        if(nil == cell){
            cell = [[UITableViewCell alloc]
                    initWithStyle:UITableViewCellStyleSubtitle
                  reuseIdentifier:cellID];
        }
    
        //    setting default image while main photo is loading
        cell.imageView.image = [UIImage imageNamed:@"default.png"];
    
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
            NSString* imgPath = _userFriends[(NSUInteger)indexPath.row][@"photo"];
            NSData* img = [NSData dataWithContentsOfURL:[NSURL URLWithString:imgPath]];
    
            dispatch_async(dispatch_get_main_queue(), ^{
                cell.imageView.image = [UIImage imageWithData:img];
            });
        });
    
        NSString* firstName = _userFriends[(NSUInteger)indexPath.row][@"first_name"];
        NSString* lastName = _userFriends[(NSUInteger)indexPath.row][@"last_name"];
        NSString* fullName = [NSString stringWithFormat:@"%@ %@", firstName, lastName];
        cell.textLabel.text = fullName;
    
        NSString* status = _userFriends[(NSUInteger)indexPath.row][@"status"];
        cell.detailTextLabel.text = status;
    
        return cell;
    }
    
    @end
    </code>
    Всё должно запускаться на ура. Переходим к следующему шагу.

    Интегрирование ВКонтакте iOS SDK v2.0
    Забираем исходники по этой ссылке.

    Подключаем QuartzCore.framework
    image

    Добавляем Vkontakte iOS SDK
    image

    В ASAAppDelegate.h добавляем два протокола:
    <code class="objectivec">@interface ASAAppDelegate : UIResponder <UIApplicationDelegate, VKConnectorDelegate, VKRequestDelegate>
    </code>

    Открываем файл реализации ASAAppDelegate.m и вставляем следующие строки в метод
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    :
    <code class="objectivec">    [[VKConnector sharedInstance]
                      setDelegate:self];
        [[VKConnector sharedInstance] startWithAppID:@"3541027"
                                          permissons:@[@"friends"]];
    </code>
    Данный код при запуске приложения покажет всплывающее окно пользователю для авторизации в социальной сети ВКонтакте.
    image

    В  ASAAppDelegate.m реализуем еще два метода:
    <code class="objectivec">#pragma mark - VKConnectorDelegate
    
    - (void)        VKConnector:(VKConnector *)connector
    accessTokenRenewalSucceeded:(VKAccessToken *)accessToken
    {
    //   now we can make request
        [[VKUser currentUser] setDelegate:self];
        [[VKUser currentUser] friendsGet:@{
                @"uid"    : @([VKUser currentUser].accessToken.userID),
                @"fields" : @"first_name,last_name,photo,status"
        }];
    }
    
    #pragma mark - VKRequestDelegate
    
    - (void)VKRequest:(VKRequest *)request
             response:(id)response
    {
        ASAViewController *controller = (ASAViewController *)self.window.rootViewController;
    
        controller.userFriends = response[@"response"];
        [controller.tableView reloadData];
    }
    </code>
    Окончательный вид ASAAppDelegate.h и ASAAppDelegate.m на данном этапе:
    <code class="objectivec">#import <UIKit/UIKit.h>
    #import "VKConnector.h"
    #import "VKRequest.h"
    
    @class ASAViewController;
    
    @interface ASAAppDelegate : UIResponder <UIApplicationDelegate, VKConnectorDelegate, VKRequestDelegate>
    
    @property (strong, nonatomic) UIWindow *window;
    @property (strong, nonatomic) ASAViewController *viewController;
    
    @end
    </code>
    <code class="objectivec">#import "ASAAppDelegate.h"
    #import "ASAViewController.h"
    #import "VKUser.h"
    #import "VKAccessToken.h"
    
    
    @implementation ASAAppDelegate
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    
        // Override point for customization after application launch.
        self.viewController = [[ASAViewController alloc] initWithNibName:@"ASAViewController" bundle:nil];
        self.window.rootViewController = self.viewController;
        [self.window makeKeyAndVisible];
    
        [[VKConnector sharedInstance]
                      setDelegate:self];
        [[VKConnector sharedInstance] startWithAppID:@"3541027"
                                          permissons:@[@"friends"]];
    
        return YES;
    }
    
    #pragma mark - VKConnectorDelegate
    
    - (void)        VKConnector:(VKConnector *)connector
    accessTokenRenewalSucceeded:(VKAccessToken *)accessToken
    {
    //   now we can make request
        [[VKUser currentUser] setDelegate:self];
        [[VKUser currentUser] friendsGet:@{
                @"uid"    : @([VKUser currentUser].accessToken.userID),
                @"fields" : @"first_name,last_name,photo,status"
        }];
    }
    
    #pragma mark - VKRequestDelegate
    
    - (void)VKRequest:(VKRequest *)request
             response:(id)response
    {
        ASAViewController *controller = (ASAViewController *)self.window.rootViewController;
    
        controller.userFriends = response[@"response"];
        [controller.tableView reloadData];
    }
    
    @end
    </code>
    Запускаем приложение и видим примерно следующее (не забывайте, что в указанном выше примере не используется кэширование запросов намеренно):
    image
    image

    Десерт из Core Data
    Вот мы и подошли к самому интересному и увлекательному! Надеюсь Вы еще не потеряли желание доделать практическую часть ;) Отвлекитесь, выпейте чайку с сушками, погрызите конфетку, разомнитесь, подтянитесь.

    Зачем нам здесь Core Data? Мы поступим следующим образом: при первом запросе к серверу ВКонтакте мы получим список друзей и запрашиваемые поля (статус, фотография, имя, фамилия), эту информацию сохраним в локальном хранилище используя Core Data, а потом запустим приложение и во время запроса отключим интернет и выведем список друзей пользователя, которые были сохранены локально во время первого запроса. Идёт? Тогда приступим.

    Для обработки факта отсутствия интернет соединения мы воспользуемся следующим методом из протокола VKRequestDelegate:
    <code class="objectivec">- (void)VKRequest:(VKRequest *)request
            connectionErrorOccured:(NSError *)error
    {
    //    TODO
    }
    </code>
    Тело метода мы напишем немного позже.

    Ах да, совсем забыл! Подключаем  
    CoreData.framework
    .
    image
    Добавляем три любимые нами свойства в ASAAppDelegate.h:
    <code class="objectivec">@property (nonatomic, strong) NSManagedObjectModel *managedObjectModel;
    @property (nonatomic, strong) NSPersistentStoreCoordinator *coordinator;
    @property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
    </code>

    Теперь переходим в ASAAppDelegate.m для того, чтобы реализовать явные геттеры для всех трёх свойств.
    Managed Object Model:
    <code class="objectivec">- (NSManagedObjectModel *)managedObjectModel
    {
        if(nil != _managedObjectModel)
            return _managedObjectModel;
    
        _managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
        
        return _managedObjectModel;
    }
    </code>
    Persistent Store Coordinator:
    <code class="objectivec">- (NSPersistentStoreCoordinator *)coordinator
    {
        if(nil != _coordinator)
            return _coordinator;
    
        NSURL *storeURL = [[[[NSFileManager defaultManager]
                                            URLsForDirectory:NSDocumentDirectory
                                                   inDomains:NSUserDomainMask]
                                            lastObject]
                                            URLByAppendingPathComponent:@"BasicApplication.sqlite"];
    
        _coordinator = [[NSPersistentStoreCoordinator alloc]
                                                      initWithManagedObjectModel:self.managedObjectModel];
    
        NSError *error = nil;
        if(![_coordinator addPersistentStoreWithType:NSSQLiteStoreType
                                       configuration:nil
                                                 URL:storeURL
                                             options:nil
                                               error:&error]){
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
    
        return _coordinator;
    }
    </code>
    Managed Object Context:
    <code class="objectivec">- (NSManagedObjectContext *)managedObjectContext
    {
        if(nil != _managedObjectContext)
            return _managedObjectContext;
    
        NSPersistentStoreCoordinator *storeCoordinator = self.coordinator;
    
        if(nil != storeCoordinator){
            _managedObjectContext = [[NSManagedObjectContext alloc] init];
            [_managedObjectContext setPersistentStoreCoordinator:storeCoordinator];
        }
    
        return _managedObjectContext;
    }
    </code>

    Build… И… и… всё нормально.

    Теперь переходим к созданию модели. Кстати, хочу отметить, что я делаю всё без страховки и, может быть в конце что-то с чем-то и не состыкуется, но мы же смелые программисты!
    Для создания модели нам понадобиться тот самый XCode.
    Открываем наш проект в нём, нажимаем Control+N и выбираем Core Data -> Data Model:
    image

    Сохраним модель под названием Friend:
    image

    Видим уже довольно знакомый экран:
    image

    Создадим новую сущность под названием Friend и добавим 4 свойства: last_name (String), first_name (String), status (String), photo (Binary Data).
    image

    Завершаем и закрываем XCode.

    Следующее, что мы должны сделать, так это сохранить данные о пользователях после осуществления запроса.
    Открываем ASAAppDelegate.m, спускаемся к метод VKRequest:response: и изменяем его следующим образом:
    <code class="objectivec">- (void)VKRequest:(VKRequest *)request
             response:(id)response
    {
        ASAViewController *controller = (ASAViewController *)self.window.rootViewController;
    
        controller.userFriends = response[@"response"];
        [controller.tableView reloadData];
    
    //    сохраняем данные в фоне, чтобы не замораживать интерфейс
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
            for(NSDictionary *user in controller.userFriends){
                NSManagedObject *friend = [NSEntityDescription insertNewObjectForEntityForName:@"Friend"
                                                                        inManagedObjectContext:self.managedObjectContext];
    
                [friend setValue:user[@"first_name"] forKey:@"first_name"];
                [friend setValue:user[@"last_name"] forKey:@"last_name"];
                [friend setValue:[NSData dataWithContentsOfURL:[NSURL URLWithString:user[@"photo"]]] forKey:@"photo"];
                [friend setValue:user[@"status"] forKey:@"status"];
    
                NSLog(@"friend: %@", friend);
            }
    
            if([self.managedObjectContext hasChanges] && ![self.managedObjectContext save:nil]){
                NSLog(@"Unresolved error!");
                abort();
            }
        });
    }
    </code>
    На каждой итерации мы создаём новый объект, устанавливаем его поля и сохраняем. В консоли можете наблюдать радующие глаз строки:
    image

    Такс, осталось доработать отображение таблицы при обрыве интернет соединения. Весь код пойдёт в метод
    - (void)VKRequest:(VKRequest *)request connectionErrorOccured:(NSError *)error
    и будет выглядеть следующим образом:
    <code class="objectivec">- (void)VKRequest:(VKRequest *)request
            connectionErrorOccured:(NSError *)error
    {
    //    понадобится нам для хранения словарей с пользовательской информацией
        NSMutableArray *data = [[NSMutableArray alloc] init];
    
    //    конфигурируем запрос на получение друзей
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]
                                                        initWithEntityName:@"Friend"];
        NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"last_name"
                                                                         ascending:YES];
        [fetchRequest setSortDescriptors:@[sortDescriptor]];
    
    //    осуществляем запрос
        NSArray *tmpData = [self.managedObjectContext executeFetchRequest:fetchRequest
                                                                    error:nil];
    
    //    обрабатываем запрос
        for(NSManagedObject *object in tmpData){
    //        эта строка здесь потому, что у меня в друзьях есть удаленный пользователь - мудак :)
            if([object valueForKey:@"status"] == nil)
                continue;
    
            NSDictionary *tmp = @{
                    @"last_name": [object valueForKey:@"first_name"],
                    @"first_name": [object valueForKey:@"last_name"],
                    @"photo": [object valueForKey:@"photo"],
                    @"status": [object valueForKey:@"status"]
            };
    
            [data addObject:tmp];
        }
    
    //    теперь данные "перебросим" в нужный контроллер
        ASAViewController *controller = (ASAViewController *)self.window.rootViewController;
        controller.userFriends = data;
        [controller.tableView reloadData];
    }
    </code>

    И небольшие коррективы внести надо в метод
    - (UITableViewCell *)tableView:(UITableView *)tableView
      cellForRowAtIndexPath:(NSIndexPath *)indexPath
    :
    <code class="objectivec">- (UITableViewCell *)tableView:(UITableView *)tableView
      cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *cellID = @"friendID";
    
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
        if(nil == cell){
            cell = [[UITableViewCell alloc]
                    initWithStyle:UITableViewCellStyleSubtitle
                  reuseIdentifier:cellID];
        }
    
        //    setting default image while main photo is loading
        cell.imageView.image = [UIImage imageNamed:@"default.png"];
    
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
            NSData *img;
    
            if([_userFriends[(NSUInteger) indexPath.row][@"photo"] isKindOfClass:[NSData class]]){
                img = _userFriends[(NSUInteger) indexPath.row][@"photo"];
            } else {
                NSString* imgPath = _userFriends[(NSUInteger)indexPath.row][@"photo"];
                img = [NSData dataWithContentsOfURL:[NSURL URLWithString:imgPath]];
            }
    
            dispatch_async(dispatch_get_main_queue(), ^{
                cell.imageView.image = [UIImage imageWithData:img];
            });
        });
    
        NSString* firstName = _userFriends[(NSUInteger)indexPath.row][@"first_name"];
        NSString* lastName = _userFriends[(NSUInteger)indexPath.row][@"last_name"];
        NSString* fullName = [NSString stringWithFormat:@"%@ %@", firstName, lastName];
        cell.textLabel.text = fullName;
    
        NSString* status = _userFriends[(NSUInteger)indexPath.row][@"status"];
        cell.detailTextLabel.text = status;
    
        return cell;
    }
    </code>

    Ура! Приложение завершено и выводит оно друзей из локального хранилища:
    image

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

    Надеюсь, что спина и пальцы не устали.
    Надеюсь, что Вы довольны проведенным временем в компании c Core Data.
    Надеюсь, что Вы хотите видеть продолжения.

    Примечание
    Ничто не может радовать автора, как оставленный комментарий, даже если это критика ;)

    Благодарю за внимание!

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Из песочницы] Автоматическая генерация кода в Yii

    Привет, %username%! Несколько лет назад я познакомился с замечательным фреймворком Yii и с тех пор как только у меня появляется возможность вести проект на нем — я дерусь берусь за нее.

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

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

    Giix

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

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

    Основные фичи
    • Улучшенная и упрощенная i18n
    • Поддержка связей HAS_MANY и MANY_MANY.
    • Встроенная поддержка для сохранения связей MANY_MANY при помощи нового метода GxActiveRecord::saveWithRelated.
    • Правильная обработка связанных атрибутов моделей, рендеринг соответствующих полей формы основываясь на типе связей.
    • Удобная структура моделей для дальнейшей работы

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

    Manymanyajaxcrudadmin

    Страница расширения
    Достаточно крутая штука. Предоставляет шаблон для генерации кода с использованием ajax в фронтенде для моделей со связками MANY_MANY. Удобно когда нужно создать сущность к примеру «продукт» или «категория».

    К примеру для продукта мы используем обычный CListView или CGridView а для категорий можем использовать nestedset, редактируемые при помощи плагина jstree.

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

    Заключение

    Моделей и наборов шаблонов для генерации намного больше, я описал лишь те которые приходилось использовать и которые мне действительно нравятся.
    Идея форка для Giix не покидает меня, есть действительно хорошие идеи по-поводу данного расширения к примеру: добавить настройку типов полей перед генерацией, настройка правил, фильтров, возможно это стоит оформить как новый модуль для yii2. Время покажет.

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

    :
    manymanyajaxcrudadmin
    giix
    Автоматическая генерация кода в Yii

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Сколько налогов вы платите с зарплаты?

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

    На мой взгляд, люди должны знать – сколько и за что конкретно они платят. У нас считается, будто работник платит со своей зарплаты только один налог – НДФЛ, равный 13%.

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

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

    Рассмотрим вариант трудоустройства Васи Пупкина в ООО «Рога и Копыта» с зарплатой в сто тысяч рублей.

    Фактическая Заработная плата 135 135,13р.
    ФБ 6% 8 108,11р.
    ПФР 14% 18 918,92р.
    ТФОМС 2% 2 702,70р.
    ФФОМС 1.1% 1 486,49р.
    ФСС 2,9% 3 918,92р.
    уплачено государству 26% 35 135,13р.
    белая зарплата сотрудника 100 000,00р. именно эта сумма и фигурирует в договоре с сотрудником.
    НДФЛ 13% 13 000,00р.
    к Выдаче работнику 87 000,00р.

    Если вам начислено 100.000 руб. зарплаты, на руки вы получите 87.000 руб., а государству перечислите 48.135,13 руб. За год вы получите на руки 1.044.000 руб., и заплатите государству – 577.621,56 руб.

    плюсом стоит отметить что практически в каждом товаре купленном в магазине присутствует 18% НДС. которые вы тоже платите государству из заработанных денег.

    Так что с определенной долей погрешности можно утверждать что работающий гражданин в том или ином виде отдает государству 50-60% заработанных денег.

    Много это или мало? Вопрос как говорится риторический.
    Но учитывая с какой частотой наши чиновники покупают себе машины по 3-5 миллиона рублей — живут они не плохо на наши налоги.

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


    update: как справедливо указал Keeperovod все выше написанное относится к 2012му году
    с 2013 го ЕСН отменен и суммарно составляет 30%
    Согласно Закону № 212-Ф3 от 24.07.2009 года ЕСН отменен, вместо него введены страховые взносы в ПФР, в ФФОМС и ТФОМС, в ФСС. 1 января 2010 года Закон вступил в силу. Отчисления ЕСН производились в размере 26%, на 2013 год суммарная ставка страховых взносов составит 30%, за исключением предприятий, попадающих под условия пониженного тарифа.


    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    Другие планеты

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

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

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





    В 63 световых годах от старушки Земли, в созвездии Лисичка (Vulpecula) расположена небольшая звезда примерно на? меньше Солнца, с милым названием HD 189773. Вокруг неё вращается газовая планета, обнаруженная в 2007 году и названная столь же остроумно: HD 189773b. Её существование как раз и обнаружили благодаря прохождению на фоне диска звезды. Являясь одной из ближайших к нам известных экзопланет, HD 189773b заслужила честь первой предстать, так сказать, в своём истинном виде. Такие газовые планеты, сравнимые по размерам с Юпитером и вращающиеся на достаточно небольшом расстоянии от своих звёзд, астрономы прозвали горячими Юпитерами. По оценкам учёных, планеты такого типа должны быть довольно распространены во Вселенной.

    Для определения цвета планеты, астрономам пришлось сначала отделить мух от котлет очистить спектр отражённого планетой света от спектра самой звезды. Для этого с помощью спектрографа орбитального телескопа Хаббл (Hubble) просканировали данную звёздную систему до, во время и после прохождения планеты на фоне звезды. Это стало возможным благодаря удачному расположению плоскости орбиты. Яркость свечения HD 189773b составляет примерно 0,0001 от яркости её родительской звезды. Проанализировав спектральный состав излучения в этих трёх случаях и альбедо планеты, учёные выяснили, что HD 189773b имеет лазурно-голубой цвет. Чем-то она похожа из космоса на Бледную голубую точку. Однако на этом сходство кончается. В нашем с вами случае голубой цвет обусловлен наличием воды в атмосфере и на поверхности планеты. По контрасту с уютной Землёй, HD 189773b можно назвать одним из филиалов ада. Посудите сами:
    • Планета представляет собой газовый гигант наподобие нашего Юпитера.
    • Из-за близости к своей звезде, температура на поверхности HD 189773b составляет 1000 градусов Цельсия, а разница температур между дневной и ночной сторонами достигает 260 градусов.
    • Плотная туманная атмосфера толщиной около 1000 км (атмосфера Земли имеет толщину 120 км) бурлит огромными турбулентностями с ветрами, дующими со скоростью 7000 км/час. Для сравнения, самый мощный зарегистрированный тайфун в истории человечества — Тип 1979 —достигал скорости 300 км/час.
    • Сам туман, заполняющий атмосферу планеты, состоит из мельчайших (менее 0,001 мм) частиц железа, соединений кремния, а также оксида алюминия, из которого на Земле состоят сапфиры.
    • Всё это подвергается мощнейшему потоку ультрафиолета, который в 20 раз превышает «земной» уровень. А рентгеновское излучение, падающее на HD 189773b, в 3 миллиона (!) раз выше, чем на Земле.

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



    А кто ещё?
    Увы, пока что это первое и единственное исследование подобного рода. Несмотря на то, что астрономам сейчас известно немногим менее 900 экзопланет, цвета их нам пока неизвестны. Тому есть разные причины, среди которых ограниченные возможности приборов наблюдения не всегда играют главную роль. Возьмём, например, ближайшую к нам звёздную систему — Альфа Центавра. Она расположена всего лишь в 4,4 световых годах от Солнца, а не в 63, как HD 189773. Благодаря своей близости к нам и достаточной яркости, Альфа Центавра испокон веков была объектом наблюдения астрономов. Но лишь в прошлом году в этой звёздной системе обнаружили планету. Оказывается, всё это время её было невозможно обнаружить по причине того, что она расположена слишком близко к своей звезде. В результате излучение звезды настолько превышает интенсивность отражённого планетой света, что для её обнаружения потребовалось 4 года непрерывных наблюдений с помощью спектрографа HARPS, специально созданного для тончайших измерений с целью поиска экзопланет. Близость к звезде также является причиной того, что температура на поверхности этой планеты достигает 1200 градусов Цельсия.

    Сегодня наши сведения об экзопланетах крайне ничтожны. Количество звёзд в одной только нашей галактике Млечный Путь приблизительно оценивается в 100-400 миллиардов. Последние исследования говорят о том, что средняя температура по больнице в среднем на одну звезду приходится 1,6 планеты, так что потенциально в Млечном Пути имеется примерно 500 миллиардов планет. Правда, как видно из двух приведённых выше примеров, далеко не все планеты «одинаково полезны» с практической точки зрения. Сегодня считается, что количество потенциально пригодных для обитания планет в нашей галактике может достигать 17 миллиардов (в этом месте все уфологи дружно выдыхают).

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





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



    Земля в иллюминаторе
    Поскольку мы всё ещё формально одиноки во Вселенной, единственным сегодня небесным телом, цвет которого определяется не только химическим составом атмосферы и поверхности, является Земля. В немалой степени красоту нашему дому придаёт зелёный цвет растительности. Почти четверть площади нашей планеты покрывает Царство Хлорофилла. Значение его для нас и всей нашей планеты известно каждому. Учитывая бесконтрольный рост населения, перед человечеством всё больше начинают маячить нехватка не нефти и газа, а еды и питьевой воды. И самые людные места на планете, Африка, Индия и Китай, оказываются совсем в незавидном положении. Войны будущего, вероятно, назовут «водяными» войнами. Но это тема для совсем другой статьи.

    Источник: habrahabr.ru,
    получено с помощью rss-farm.ru


    [Перевод] Ужесточение правил для разработчиков Google Play. Полный запрет push-рекламы

    Google вводит крупное для разработчиков контента Play Store, устраняет рекламу из панели уведомлений (на этот раз точно) и другое.


    На днях компания Google выпустила крупное обновление правил программы для разработчиков приложений для Google Play. Неважно, кто вы — пользователь или разработчик — следует знать об этих измнениях. Политика в отношении контента в основном сводится к гугловскому подходу «Это то, что мы не разрешаем в Play Store». Теперь вы понимаете, насколько важно быть в курсе. Google регулярно вносит обновления в эту политику, но, я думаю, это самое грандиозное изменение, которое мы могли только наблюдать. Было затронуто и изменено множество областей, что повлекло за собой значительные последствия.


    Итак, начнем с того, для чего, вероятно, вы и читаете этот материал.

    Замечание: Эти изменения в отношении Play Store вступают в силу через 30 дней для существующих приложений, а именно 23 сентября 2013 года, и безотлагательно — для новых приложений, выпущенных, начиная с этого дня.

    Google устраняет рекламные уведомления AirPush и других рекламных сетей (на этот раз точно)
    Компанию расстраивает тот факт, что приложения используют панель уведомлений для рекламы. И на этот раз она намерена покончить с этим раз и навсегда.
    «Приложения не должны отображать на устройстве пользователя рекламные объявления посредством уведомлений системного уровня, если только уведомления не являются неотъмлемой чертой установленного приложения (например, приложение авиакомпании уведомляет своих пользователей-клиентов о выгодных ценах, или игра оповещает пользователей о проводимых акциях)»

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

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

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

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

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

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