...

суббота, 12 октября 2013 г.

[Перевод] Что нового в Objective-C и Foundation принесла iOS 7

Что нового в Objective-C и Foundation принесла iOS 7

Objective-C является наиболее распространенным языком для разработки iOS и OS X приложений. Конечно, можно использовать сторонние фреймворки, которые позволяют разрабатывать приложения с использованием других языков, таких как HTML и JavaScript или C#, но если вы хотите написать невероятно быстро, эффективные приложения, то вам нужно использовать Objective-C.


Foundation является одним из основных структур, которые вы будете использовать при разработке приложений на языке Objective-C.


Как IOS разработчик, Вы должны быть в курсе актуальных и последних достижений в Objective-C и Foundation, в IOS 7 есть некоторые важные изменения которые нужно знать.


В этой статье мы сделаем краткий обзор некоторых новых функций в Objective-C и Foundation.


Давайте начнем!


Модули / Modules


Велика вероятность, что вы писали #import тысячу раз и более:



#import <UIKit/UIKit.h><br>
#import <MapKit/MapKit.h><br>
#import <iAd/iAd.h><br>


Этот синтаксис возвращает нас к корням ObjectiveC: а именно к языку C. Оглавление предварительной обработки директивы #import, работает таким же образом, как #include. Разница лишь в том, что #import в отличии от #include не импортирует заголовки повторно, это одноразовая операция.


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


Заголовочный файл UIKit, UIKit.h импортирует все другие заголовки, которые включенные в UIKit framework. Это означает, что Вы не должны вручную импортировать каждый заголовочный файл в framework, такие как UIViewController.h, UIView.h или UIButton.h.


Вас заинтересовал размер UIKit framework? Просмотрите и посчитайте все строки кода во всех заголовках UIKit, и вы увидите, что это составляет более 11 000 строк кода!


В стандартном iOS приложении Вы импортируете UIKit в большинство своих файлов, это означает, что каждый файл будет на 11,000 строк кода больше. Это совсем не идеал для приложения; больше строк кода означает более длительное время компиляции приложения.


Оригинальное решение: Предварительно скомпилированные заголовки.


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



#import <Availability.h>

#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif

#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#endif


#warning в данном случае уведомляет разработчика, что приложение, которое он создает, предназначается для SDK до IOS 5. UIKit и заголовочные файлы Foundation — часть этого запаса PCH, так как каждый файл в Вашем приложении будет использовать Foundation, и большинство будут использовать UIKit. Поэтому, это хорошие дополнения к PCH, так что предварительное вычисление и кэширование принесут пользу для компиляции каждого файла в Вашем приложении.


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


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


Примечание: LLVM — набор модульного и допускающего повторное использование компилятора и toolchain технологий, связанных Xcode. У LLVM есть несколько компонентов; наиболее важными для Objective-C разработчика это Clang, собственный C, C++ и Objective C компиляторы; а также LLDB — собственный отладчик, который является лучшим другом разработчика.


Новое решение: Модули


Первое публичное появление модулей в Objective-C было в докладе, сделанным Doug Gregor от Apple в 2012 году на собрании LLVM разработчиков. Это увлекательный разговор, и он настоятельно рекомендуется для всех, кто интересуется работой своих компиляторов. Вы можете найти видео сессии в Интернете по адресу llvm.org/devmtg/2012-11/ # talk6.


Модули инкапсуляции структур во многих способах чище, чем когда-либо прежде. Больше препроцессору не необходимо заменять #import директивы со всем содержимым файла. Вместо этого, модуль обертывает framework в автономный блок, который предварительно составлен таким же образом, как PCH файл и обеспечивает такое же улучшение скорости компиляции. Тем не менее, вам больше не приходится констатировать framework который вы используете в файле PCH, вы получите увеличение скорости просто с помощью модулей.


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



  • Добавьте строку #import используемого framework.

  • Напишите код, который использует framework.

  • Скомпилируете.

  • Посмотрите, поскольку ошибки выложены во время соединения.

  • Помнить, что вы забыли слинковать framework.

  • Добавьте framework к фазе сборки проекта.

  • Скомпилировать снова.


Невероятно распространено забыть слинковать framework, но модули также решают эту проблему аккуратно. (Есть ли что-нибудь, что не могут сделать модули? )


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


Как использовать модули


Модули чрезвычайно удобны в Ваших проектах. Для существующих проектов первое, что нужно сделать, включить их. Вы можете найти эту опцию, ища modules в Build Settings Вашего проекта (удостоверяющийся выбирать All, not Basic) и затем изменить опции Enable Modules на YES, так как показанно ниже:


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


Link Frameworks Automatically эта опция может быть использована, чтобы включить или отключить автоматическое связывание фреймворков, как это описано ранее. Есть мало причин, почему вы хотите, отключить эту возможность.


Как только модули включены, вы можете начать использовать их в своем коде. Довально просто сделать это, однако есть одно небольшое изменение в синтаксисе к которому вы так привыкли. Вместо обычного синтаксиса # import, вы просто используете import:



@import UIKit;
@import MapKit;
@import iAd;


Все еще возможно импортировать некоторые framework, которой Вам необходимы. Как пример, если бы Вам нужно было импортировать просто UIView, написали бы так:



@import UIKit.UIView;


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


Прежде, чем начнете приходить в восторг от модулей, есть тот мало протеста, к сожалению. С Xcode 5.0, не возможно использовать модули с Вашими собственными frameworks или сторонними frameworks. Это, вероятно, придет в свое время — но сейчас это печальная сторона. Ничто не совершенно – даже Objective C!


Новый возвращаемый тип – instancetype


Новый тип был добавлен в Objective-C, который назвали — instancetype. Его можно только использоваться в качестве возвращаемого типа метода Objective-C и используется в качестве подсказки для компилятора, что возвращаемый тип метода будет экземпляром класса, которому принадлежит этот метод.


Примечание: Эта функция не является строго новой для Xcode 5 и IOS 7, но была украдкой брошена в недавние сборки Clang. Тем не менее, Xcode 5 отмечана в первый раз, что Apple начал использовать его на протяжении всех frameworks. Вы можете узнать больше об этой возможности на официальном сайте Clang: clang.llvm.org/docs/LanguageExtensions.html Objective-C функциями.


Почему instancetype полезный? Рассмотрите следующий пример кода:



NSDictionary *d = [NSArray arrayWithObjects:@(1), @(2), nil];
NSLog(@"%i", d.count);


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


Причина таких действий во время выполнения благодаря мощному, динамическому характеру Objective-C. Тип является чисто руководством компилятора. Метод count ищется во время выполнения в любом классе словарь переменной случается. В этом случае метод count существует, так что компилятор считает, что все будет хорошо. Однако, это может вернуться, чтобы укусить вас позже, если вы добавили код, который использует другой метод, который NSArray не имеют общего с NSDictionary, таких как objectAtIndex:. Сначала, это не будет понятно, где именно лежит вопрос.


Но почему компилятор не выяснить, что экземпляр возвращается + [arrayWithObjects NSArray:] не является экземпляром NSDictionary? Ну, это потому, что его сигнатура метода заключается в следующем:



+ (id)arrayWithObjects:(id)firstObj, ...;


Обратите внимание на тип возвращаемого значения это ID. Тип ID это значение любой Objective-C класс, он не должны быть даже подклассом NSObject. Он в буквальном смысле не имеет информации о типе, кроме того, это экземпляр Objective-C класса. Для этого, чтобы быть полезным, компилятор выдает предупреждения, когда вы неявно приводите к ID для конкретного типа, например NSDictionary * в приведенном выше примере. Если бы это выдавало предупреждение, идентификатор типа id был бы в значительной степени бесполезным.


Но почему возвращаемый тип метода в первую очередь ID? Это чтобы вы могли успешно подкласс метод и до сих пор использовать его без проблем. Чтобы продемонстрировать, почему так, рассмотрим следующий подкласс класса NSArray:



@interface MyArray : NSArray
@end


Теперь рассмотрим использование вашего нового подкласса в коде ниже:



MyArray *array = [MyArray arrayWithObjects:@(1), @(2), nil];


Ах — теперь вы видите, почему возвращаемый тип arrayWithObjects: должен быть ID. Если бы это был NSArray *, то подклассы потребует, чтобы быть приведен к необходимому классу. Это где новый возвращаемый тип instancetype приходит внутри.


Если вы посмотрите на файл заголовка для NSArray в IOS 7.0 SDK, вы заметите, сигнатуры метода для этого метода изменилось на следующее:



+ (instancetype)arrayWithObjects:(id)firstObj, ...;


Единственная разница — тип возврата. Этот новый тип возврата который обеспечивает подсказку для компилятора, что возвращаемое значение будет экземпляром класса, к которому методу обращаются. Таким образом, когда arrayWithObjects: обращен NSArray, тип возврата выведен, чтобы быть NSArray *; если обращался к MyArray, тип возврата выведен, чтобы быть MyArray * и т.д.


Это работает по всему проблема с идентификатор типа id при поддержании возможности разделить на подклассы успешно. Если скомпилируете исходный код в Xcode 5, вы теперь увидите следующее предупреждение:


warning: incompatible pointer types initializing 'NSDictionary *' with an expression of type 'NSArray *' [-Wincompatible-pointer-types] NSDictionary *d = [NSArray arrayWithObjects:@(1), @(2), nil]; ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


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


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


Стремитесь использовать instancetype как можно больше; это стало стандартом для Apple — и никогда не знаете, когда это сохранит некоторое болезненное время для отладки.


Новый Foundations


Оставшаяся часть этой статьи посвящена различным новым частям и функциям в Foundation, базовая основа всех Objective-C разработчиков. Трудно разрабатывать Objective-C приложений без Foundation, так как все IOS приложения требует ее использования. Поиск новых драгоценных камней в Foundation является большой частью удовольствия от получения на руки нового выпуска IOS SDK!


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


Далее в этом разделе описываются другие интересные дополнения и изменения в Foundation.


NSArray


Попытка получить объект от экземпляра NSArray выдаст исключение, если индекс, который предоставляете, будет вне длины массива. Будете также часто находить потребность получить доступ к первым и последним объектам массива, такой как тогда, когда используете непостоянный массив, чтобы содержать очередь. В первым прибыл — первым убыл (FIFO) очереди выталкиваете объекты от передней стороны массива, и в первым пришел — последним вышел (FILO) выталкиваете объекты от конца массива.


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



NSMutableArray *queue = [NSMutableArray new];

// ...

if (queue.count > 0) {
id firstObject = [queue objectAtIndex:0];
// Use firstObject
}

// ...

if (queue.count > 0) {
id lastObject = [queue objectAtIndex:(queue.count - 1)];
// Use lastObject
}


В случае получения последнего объекта всегда имели опцию использования следующего метода NSArray:



- (id)lastObject;


Каждый в мире разработчики Objective-C — не сомненно будет рад, что впервые у него есть доступ к эквивалентному методу, чтобы получить первый объект массива:



- (id)firstObject;


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


Примечание: Если вы внимательно посмотрите на заголовок NSArray вы увидите, что на самом деле метод firstObject был примерно с IOS 4.0, но он не был опубликован аж до IOS 7. Поэтому вы могли бы получить метод до IOS 7, но это потребовало бы объявить селектор firstObject в одном из ваших собственных файлов заголовка, чтобы сообщить компилятору, что она на самом деле существует. Такой подход конечно не рекомендуется, так что это хорошо, что Apple, наконец принес его из сокрытия.


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



NSMutableArray *queue = [NSMutableArray new];
// ...

id firstObject = [queue firstObject];
// Use firstObject

id lastObject = [queue lastObject];
// Use lastObjec


NSData


Data — одна из тех вещей, с которыми Вы имеете дело каждый день, когда программируете. NSData — Фундаментальный класс, который инкапсулирует необработанные байты и обеспечивает методы для того, чтобы Вы управляли этими байтами, также читая и записывали данные в файл. Но одной очень общей задачей, для которой не было никакой собственной реализации, является кодирование и декодирование Base64. По крайней мере, это имело место до выпуска iOS 7


Base64 — группа схем кодирования двоичного файла к тексту, которые представляют двоичных данных в формате ASCII. Эти схемы обычно используются, где есть потребность закодировать двоичных данных, которые будут сохранены на или переданы по носителям, разработанным, чтобы иметь дело исключительно с текстовыми данными. Это удостоверилось, что данные остаются неповрежденными без модификации во время транспорта. Наиболее популярный способ использования кодирования Base64 обрабатывает присоединения в электронном письме, а также кодирует маленькие изображения, которые являются частью ответа JSON, возвращенного веб-API.


До iOS 7.0, Base64 кодирующие и декодирующие задачи потребовали, чтобы реализовали свой собственный метод или включали часть сторонней платформы. Типичным способом Apple это теперь очень удобно эта функциональность. Следующим образом есть четыре базовых метода Base64:



- (id)initWithBase64EncodedString:(NSString *)base64String
options:(NSDataBase64DecodingOptions)options;

- (NSString *)base64EncodedStringWithOptions:
(NSDataBase64EncodingOptions)options;


- (id)initWithBase64EncodedData:(NSData *)base64Data
options:(NSDataBase64DecodingOptions)options;

- (NSData *)base64EncodedDataWithOptions:
(NSDataBase64EncodingOptions)options;


Первые два метода имеют дело со строками, в то время как последние два имеют дело с закодированными данными UTF-8. Обе пары методов выполняют то же действие, но иногда использование того или иного окажется более эффективным. Если были к Base64, кодируют строку и затем пишут ее в файл, можете решить использовать пару, которая обрабатывает закодированные данные UTF-8. С другой стороны, если были к Base64, кодируют строку и затем используют это в некотором JSON, можете решить использовать пару, которая обрабатывает строки.


Таким образом, если когда-либо успользовали два метода Base64 в Вашем проекте, теперь время, чтобы удалить тот ненужный код и использовать реализацию Apple вместо Вашего кода!


NSTimer


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


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



- (NSTimeInterval)tolerance;
- (void)setTolerance:(NSTimeInterval)tolerance;


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


NSProgress


Не так часто, что полностью новые классы добавлены к Foundation. Это — довольно устойчивая платформа, главным образом потому что новые базовые классы не требуются слишком часто. Однако, iOS 7.0 приносит полностью новый класс под названием NSProgress.


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


Структура NSProgress


Самый простой способ использовать NSProgress состоит в том, чтобы использовать его, чтобы сообщить о достижениях по ряду задач. Например, если Вы имеете 10 задач завершонных, затем можете сообщить о прогрессе, поскольку каждая задача завершается. Поскольку каждая задача завершается, прогресс восстанавливает работоспособность на 10%. Затем используя Key Value Observing (KVO) экземпляра NSProgress, будете уведомлены об этом происходящем увеличении. Могли бы использовать это уведомление в качестве возможности обновить индикатор выполнения или установить текст на метке, чтобы дать информацию относительно прогресса.


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


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


Создание отчетов о прогрессе


Использование NSProgress просто. Все начинается со следующего метода:



+ (NSProgress *)progressWithTotalUnitCount:(int64_t)unitCount;


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



NSArray *array = /* ... */;

NSProgress *progress =
[NSProgress progressWithTotalUnitCount:array.count];

[array enumerateObjectsUsingBlock:
^(id obj, NSUInteger idx, BOOL *stop) {
// Perform an expensive operation on obj
progress.completedUnitCount = idx;
}];


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


Получение обновлений прогресса


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



@property (readonly) double fractionCompleted;


Это возвращает значение от 0 до 1, указывая общий прогресс задачи. Когда нет никаких дочерних экземпляров в игре, fractionCompleted — просто завершенное количество модуля, разделенное на общее количество модуля.


Key Value Observing (KVO) — лучший путь, который будет уведомлен, когда свойство fractionCompleted изменяет свое значение. Выполнение так просто. Все, что должны сделать, зарегистрироваться как наблюдатель fractionCompleted свойства соответствующего объекта NSProgress так:



[_progress addObserver:self
forKeyPath:@"fractionCompleted"
options:NSKeyValueObservingOptionNew
context:NULL];


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



- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if (object == _progress) {
// Handle new fractionCompleted value
return;
}

// Always call super, incase it uses KVO also
[super observeValueForKeyPath:keyPath
ofObject:object
change:change
context:context];
}


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


Конечно, это важно помнить, чтобы удалить из KVO как только вы закончите, вот так:



[_progress removeObserver:self forKeyPath:@"fractionCompleted" context:NULL];


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


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


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



[Из песочницы] Как настроить Firewall для VPN-а на сервере с двумя IP

image

Я наконец-то завёл себе сервер. На нем разместил сайт своей «компании», а пососедству решил поднять VPN. Для етого был заказан второй IP. На первом у меня будет web, mail, ssh а с второго будет ходить VPN трафик. Задумка простая, но хорошего описания такой конфигурации я так и не нашел. Под катом, я покажу как настроить Shorewall чтобы VPN трафик шел только в интернет, и не мог свободно ходить на сосендий IP.



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


Давайте сперва посмотрим на ifconfig. Там мы видим два наших IP-шника, «1.1.1.1» и «2.2.2.2». Они оба идут напрямую в интернет. Сейчас они «близнецы», то есть если какой-нибудь сервис крутится на первом, он будет виден и на втором IP.



# ifconfig
eth0 Link encap:Ethernet HWaddr хх:хх:хх:хх:хх:хх
inet addr:1.1.1.1 Bcast:1.1.1.255 Mask:255.255.255.0
inet6 addr: fe80::ххх:хххх:хххх:хххх/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:417428 errors:0 dropped:230 overruns:0 frame:0
TX packets:17595 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:28249193 (28.2 MB) TX bytes:4653027 (4.6 MB)

eth0:0 Link encap:Ethernet HWaddr хх:хх:хх:хх:хх:хх
inet addr:2.2.2.2 Bcast:2.2.2.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:507 errors:0 dropped:0 overruns:0 frame:0
TX packets:507 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:44121 (44.1 KB) TX bytes:44121 (44.1 KB)




Давайте ето дело прикроем, так чтобы 1.1.1.1 пропускал на web, email, ssh, а 2.2.2.2 слушал vpn. Вот такая конфигурация:

# cat /etc/shorewall/interfaces
#ZONE INTERFACE BROADCAST OPTIONS
net4 eth0 detect tcpflags,logmartians,nosmurfs

# cat /etc/shorewall/zones
#ZONE TYPE OPTIONS IN OUT
fw firewall
net4 ipv4

# cat /etc/shorewall/policy
#SOURCE DEST POLICY LOG LIMIT: CONNLIMIT:
$FW net4 ACCEPT
net4 $FW DROP info
net4 all DROP info
# The FOLLOWING POLICY MUST BE LAST
all all REJECT info

# cat /etc/shorewall/rules
#ACTION SOURCE DEST PROTO DEST SOURCE
SECTION NEW
# ------------------------- INTERNET --------------------------------
ACCEPT net4 $FW:1.1.1.1 tcp 22
ACCEPT net4 $FW:1.1.1.1 tcp 25
ACCEPT net4 $FW:1.1.1.1 tcp 80
# ------------------------- VPN -------------------------------------
ACCEPT net4 $FW:2.2.2.2 udp 1194




Ето стандартная конфигурация, которая пропускает весь трафик с нашего VPS-a в интернет, а назад не пускает ничего, кроме того что прописано в rules. Под зоной $FW, подразумеваются оба IP, так как оба являются частью eth0 (не смотря на то что у 2.2.2.2 есть своё имя eth0:0). Для уточнения используются кострукции типа: $FW:[ip]. Вроде всё нормально. Тогда, запускаем VPN сервер, и смотрим ifconfig. Помимо того что там уже было, появился новый interface tun0:

tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:10.8.0.1 P-t-P:10.1.0.2 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:3261 errors:0 dropped:0 overruns:0 frame:0
TX packets:2624 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:351155 (351.1 KB) TX bytes:1043254 (1.0 MB)




заметьте, что интерфейс tun0 не является «близнецом» с eth0, а представляет из себя более полноценный интефейс. За етой подсетью будут сидеть VPN клиенты. Давайте подсоединимся прямо сеичас. На другом компе: проходим авторизацию, соеденение установлено, идем в терминал и пробуем подсоединится хотя бы нашему vpn gateway (10.8.0.1) чтобы почитать почту, можно пинговать если пинги принимаются (см. /etc/sysctl.conf).

$telnet 10.8.0.1 25
$sudo tail /var/log/syslog
... Shorewall:INPUT:REJECT:IN=tun0 OUT= MAC= SRC=10.8.0.6 DST=10.8.0.1 ... PROTO=TCP SPT=36879 DPT=25 ...




Наша попытка зайти на mail сервер была отвергнута, из за того что, не являсь «близнецом» eth0, tun0 не можем говорить с eth0 (и eth0:0) из за правила:

all all REJECT info




в конце /etc/shorewall/policy. Пока все правильно. Тогда добавим tun0 в shorewall.

Новая конфигурация:

# cat /etc/shorewall/interfaces
#ZONE INTERFACE BROADCAST OPTIONS
net4 eth0 detect tcpflags,logmartians,nosmurfs
vpn4 tun0 detect tcpflags,logmartians,nosmurfs #NEW

# cat /etc/shorewall/zones
#ZONE TYPE OPTIONS IN OUT
fw firewall
net4 ipv4
vpn4 ipv4 #NEW

# cat /etc/shorewall/policy
#SOURCE DEST POLICY LOG LIMIT: CONNLIMIT:
$FW net4 ACCEPT
vpn4 $FW ACCEPT #NEW
vpn4 net4 ACCEPT #NEW
net4 $FW DROP info
net4 all DROP info
# The FOLLOWING POLICY MUST BE LAST
all all REJECT info

# cat /etc/shorewall/rules
#ACTION SOURCE DEST PROTO DEST SOURCE
SECTION NEW
# ------------------------- INTERNET --------------------------------
ACCEPT net4 $FW:1.1.1.1 tcp 22
ACCEPT net4 $FW:1.1.1.1 tcp 25
ACCEPT net4 $FW:1.1.1.1 tcp 80
# ------------------------- VPN -------------------------------------
ACCEPT net4 $FW:2.2.2.2 udp 1194

# SNAT, for access to internet -- NEW
# cat /etc/shorewall/masq
#INTERFACE SOURCE ADDRESS PROTO PORT(S) IPSEC MARK
eth0 10.8.0.0/24 2.2.2.2




Что изменилось? Мы создали зону под именем vpn4 которая соответствует интерфейсу tun0. Мы декларировали vpn4 как IPv4. Мы разрешили трафику из tun0 доходить до firewall-а, и до интернета (eth0/net4). Как ни странно, нельзя разрешить только до firewall-a, а дальше по сушествуюшему правилу $fw -> net4. Надо добавить обе строки. И последнее что нам надо для полноценного выхода в интернет, ето SNAT (source address translation, когда подменяется адрес отправителя на адрес смотряшии в интернет, в нашем случае 2.2.2.2). Создаем файл masq и требуем там замены всех адресов 10.8.0.х на 2.2.2.2 при выходе из eth0 (и eth0:0).

Пробуем… Всё работает! Даже слишком… с адресом из 10.8.0.х можно заходить на 1.1.1.1:1194, чего мы никак не хотим. Мы хотели чтобы vpn трафик сперва выходил в интернет а потом бился назад через firewall. Вместо етого мы имеем vpn клиента который смотрит на наш сервер видом сзади. Почему? Потому что когда мы разрешили коммуникации типа:



# /etc/shorewall/policy:
vpn4 $FW ACCEPT #NEW




мы не уточнили на какой именно IP, так как под $FW их два (1.1.1.1 и 2.2.2.2). Ну ладно, давайте пропишем. Ан-нет, синтаксис типа: $FW:[ip] в файле policy не принемается. На етом моменте я перепробовал много всего и почти бросил затею и оставил как есть. Хотя до конца пути было очень мало. Итак, озарение: все что прописывается в policy можно точно также прописать в rules, а в rules мы можем указывать конкретные IP на firewall-e. Давайте перепишем, последняя конфигурация:

# cat /etc/shorewall/interfaces
#ZONE INTERFACE BROADCAST OPTIONS
net4 eth0 detect tcpflags,logmartians,nosmurfs
vpn4 tun0 detect tcpflags,logmartians,nosmurfs

# cat /etc/shorewall/zones
#ZONE TYPE OPTIONS IN OUT
fw firewall
net4 ipv4
vpn4 ipv4

# cat /etc/shorewall/policy
#SOURCE DEST POLICY LOG LIMIT: CONNLIMIT:
$FW net4 ACCEPT
#vpn4 $FW ACCEPT #NEW
#vpn4 net4 ACCEPT #NEW
net4 $FW DROP info
net4 all DROP info
# The FOLLOWING POLICY MUST BE LAST
all all REJECT info

# cat /etc/shorewall/rules
#ACTION SOURCE DEST PROTO DEST SOURCE
SECTION NEW
# ------------------------- INTERNET --------------------------------
ACCEPT net4 $FW:1.1.1.1 tcp 22
ACCEPT net4 $FW:1.1.1.1 tcp 25
ACCEPT net4 $FW:1.1.1.1 tcp 80
# ------------------------- VPN -------------------------------------
ACCEPT net4 $FW:2.2.2.2 udp 1194
# ------------------------- NEW -------------------------------------
ACCEPT vpn4 net4
ACCEPT vpn4 $FW:1.1.1.1 tcp 22
ACCEPT vpn4 $FW:1.1.1.1 tcp 25
ACCEPT vpn4 $FW:1.1.1.1 tcp 80

# cat /etc/shorewall/masq
#INTERFACE SOURCE ADDRESS PROTO PORT(S) IPSEC MARK
eth0 10.8.0.0/24 2.2.2.2




Что мы сделали: убрали старые разрешения из policy, и добавили разрешения в rules. Мы разрешаем весь трафик из vpn в интернет, и выборочно разрешаем трафик непосредственно на 1.1.1.1. А через интернет заходы на 1.1.1.1 послать нельзя? Нет, как бы нам ни хотелось они будут идти внутри сервера, поетому лучшее что мы можем, ето продублировать правила для интернета для трафика vpn -> 1.1.1.1. А как же трафик на 2.2.2.2? Етот трафик непосредвенно и есть vpn трафик, и он не может приходить изнутри (ето обсепечивается route-ом на клиентской машине). В других словах, клиент vpn-a никогда не пришлет трафик по направлению 10.8.0.1(vpn4) -> 2.2.2.2($fw:2.2.2.2).

Ну вот в принципе и все. Теперь мы можем спокойно браузить с «рабочего» VPN-a без использования IP-шника ведушего на «компанейский» сайт, и не боятся за обход firewall-a обычными vpn юзерами.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



Как запретить использование личных данных в рекламе Google

Вчера компания Google объявила об изменении Условий использования Google. Новые Условия вступят в силу через месяц, 11 ноября 2013 г. Согласно им Google вправе отображать фотографии и имена из личного профиля пользователей социальной сети в рекламных объявлениях, если пользователи каким-либо образом продемонстрировали связь с рекламируемым объектом.

Другими словами, если вы подписались на страницу производителя, оставили комментарий к какому-нибудь продукту, нажали на отметку «Мне нравится», проголосовали за ролик на YouTube, «лайкнули» приложение, фильм или альбом в Google Play, то через некоторое время можете обнаружить своё фото и комментарий в рекламе или отзывах к продукту.



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


Заметьте, возможность использовать личные данные профиля в рекламе по умолчанию включена, то есть явное согласие пользователя не требуется. Пользователи вполне могут быть не осведомлены относительно изменившихся правил (и в самом деле, многие ли из нас внимательно читают «Условия использования»?).

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


Для того чтобы запретить использовать своё имя в рекламе, достаточно перейти на страницу Настроек профиля Google+ и снять галочку внизу страницы: «Показывать мое имя и фото профиля в рекламе»:



Когда нажимаем «Сохранить», появляется предупреждение:



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


«Рекламные новости» стали предметом судебного иска, который подали к Facebook несколько пользователей соцсети. Пользователи утверждали, что не дали согласие на использование личных данных в рекламе. Чтобы урегулировать конфликт, Facebook пришлось выплатить истцам 20 миллионов долларов США.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



[Из песочницы] Использование Lua и C++ для обработки и хранения данных

Код статьи можно посмотреть здесь.

Чем так хорош Lua?



Когда-то я разрабатывал свою игру и задался вопросом: а какой формат данных лучше использовать?

Разработчики используют разные форматы: одни используют JSON, другие — XML, либо другие форматы данных. Ну а некоторые вообще хранят данные в .txt файлах или пишут свои парсеры. После рассмотрения различных форматов я остановился на Lua.

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


Вот, что выделяет Lua на фоне других форматов:




Начнём с простого примера, а затем я перейду к реализации класса.


Пример



Допустим, есть файл Player.lua

player = {
pos = {
X = 20,
Y = 30,
},
filename = "res/images/player.png",
HP = 20,
-- а ещё можно комментарии добавлять
}




С простым классом данные можно будет получать так:

LuaScript script("player.lua");
std::string filename = script.get<std::string>("player.filename");
int posX = script.get<std::string>("player.pos.X");


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

Почитать можно здесь.


Начнём с создания класса:



#ifndef LUASCRIPT_H
#define LUASCRIPT_H

#include <string>
#include <vector>
#include <iostream>

// Lua написан на C, поэтому нужно сообщить компилятору, чтобы он воспринимал хэдеры как код на C
extern "C" {
# include "lua.h"
# include "lauxlib.h"
# include "lualib.h"
}

class LuaScript {
public:
LuaScript(const std::string& filename);
~LuaScript();
void printError(const std::string& variableName, const std::string& reason);

template<typename T>
T get(const std::string& variableName) {
// реализация функции последует позже в статье
}
// Возращаем 0 по умолчанию
template<typename T>
T lua_get(const std::string& variableName) {
return 0;
}
// Эта функция используется в случае, если не удалось получить значение переменной и нужно вернуть какое-то
// нулевое стандартное значение
template<typename T>
T lua_getdefault(const std::string& variableName) {
return 0;
}
private:
lua_State* L;
};

#endif




Конструктор:

LuaScript::LuaScript(const std::string& filename) {
L = luaL_newstate();
if (luaL_loadfile(L, filename.c_str()) || lua_pcall(L, 0, 0, 0)) {
std::cout<<"Error: script not loaded ("<<filename<<")"<<std::endl;
L = 0;
}
}


.

Создаём lua_State, в случае если файл не был найден, либо произошла какая-либо другая ошибка, выводим сообщение об этом.

Деструктор:

LuaScript::~LuaScript() {
if(L) lua_close(L);
}


Метод printError создан для того, чтобы выводить сообщения об ошибках:



void LuaScript::printError(const std::string& variableName, const std::string& reason) {
std::cout<<"Error: can't get ["<<variableName<<"]. "<<reason<<std::endl;
}




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

template<>
inline std::string LuaScript::lua_getdefault<std::string>() {
return "null";
}




А теперь напишем шаблонную функцию get.

Разберём алгоритм на примере. Пусть нужно получить переменную «player.pos.X» из файла Player.lua

Проходим циклом до первой точки, при этом добавляя прочитанные символы в переменную «var».

«player» — таблица, которая является глобальной, поэтому получаем её с помощью lua_getglobal.

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




template <typename T>
T get(const std::string& variableName) {
if(!L) {
printError(variableName, "Script is not loaded");
return lua_getdefault<T>();
}
int level = 0;
std::string var = "";
for(unsigned int i = 0; i < variableName.size(); i++) {
if(variableName.at(i) == '.') {
if(level == 0) {
lua_getglobal(L, var.c_str());
} else {
lua_getfield(L, -1, var.c_str());
}

if(lua_isnil(L, -1)) {
printError(variableName, var + " is not defined");
return lua_getdefault<T>();
} else {
var = "";
level++;
}
} else {
var += variableName.at(i);
}
}
if(level == 0) {
lua_getglobal(L, var.c_str());
} else {
lua_getfield(L, -1, var.c_str());
}
if(lua_isnil(L, -1)) {
printError(variableName, var + " is not defined");
return lua_getdefault<T>();
}

T result = lua_get<T>(variableName);
lua_pop(L, level + 1); // pop all existing elements from stack
return result;
}




Осталось лишь добавить специализиации шаблонов(пример для некоторых типов данных):

template <>
inline bool LuaScript::lua_get<bool>(const std::string& variableName) {
return (bool)lua_toboolean(L, -1);
}

template <>
inline float LuaScript::lua_get<float>(const std::string& variableName) {
if(!lua_isnumber(L, -1)) {
printError(variableName, "Not a number");
}
return (float)lua_tonumber(L, -1);
}

template <>
inline int LuaScript::lua_get<int>(const std::string& variableName) {
if(!lua_isnumber(L, -1)) {
printError(variableName, "Not a number");
}
return (int)lua_tonumber(L, -1);
}

template <>
inline std::string LuaScript::lua_get<std::string>(const std::string& variableName) {
std::string s = "null";
if(lua_isstring(L, -1)) {
s = std::string(lua_tostring(L, -1));
} else {
printError(variableName, "Not a string");
}
return s;
}


На этом всё. Напоминаю, весь код в статье есть здесь. Там же можно найти пример использования класса.


Что дальше?



У Lua ещё много возможностей, которые я опишу во второй части статьи в ближайшем будущем. Например, получение массива данных неопределённой длины, а также получение списка ключей таблицы (например для таблицы Player из примера он был бы таким:[«pos», «filename», «HP»])

А ещё из Lua можно вызывать C++ функции, так же как и из C++ можно вызывать функции Lua, о чём я напишу в третьей части.

Удачного скриптинга!

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



Дайджест интересных материалов из мира веб-разработки и IT за последнюю неделю № 78 (6 — 12 октября 2013)

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




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


или закрыть

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



Веб 3.0 Децентрализация. Тренд на 5+ лет

Ниже я изложу ближайшие тренды развития интернета.

На дворе сейчас 2013. На горе Скайп(связь), Гугл(реклама), Пейпал(платежи), Амазон(рейтинги).

Я утверждаю что их всех завалят не конкуренты. А новая волна децентрализованных сервисов.

И каждый раз когда правители сегодняшнего мира издают мудацкий указ, или применяют силу не по делу, где-то умирает сто котят. А гидра децентрализации отращивает еще одну голову.

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


Итак. Что мы имеем.

Двадцать лет назад не было интернета. Да, были провода. Был кажется даже Яху. Но интернета не было.

Можно было зайти по модему на сайт Джона из Оклахомы и узнать как себя чувствует его котенок. Это было захватывающе. И бесполезно.

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

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

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

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


Реклама:



Незаметно произошел переворот в рекламе.

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

Такой гигант как Time Warner Inc (владелец я даже затрудняюсь сказать какого количества каналов связи, телеканалов, фильмов и прочаяя и прочаяя) стоит 62$млрд а гугл скромных 290$млрд. При этом не забываем что у гугла основной доход от рекламы. А у Тайм Варнера от чего только не.

Пришел страшный крокодил под названием WWW и сожрал всех атлантов прошлого. Хотя нет. Не сожрал.

Они остались стоять в одиночестве в своей нише. Но эта ниша перестала быть самой большой и интересной.
Платежи:



Платежные системы тоже переживали бурную эволюцию. Были банки. И чувствовали они себя великолепно.

Внезапно появляется Виза и Мастер. И ставят всех боком. У Визы капитализация 124($млрд) а например у крупнейших Bank of America (152$млрд) и HSBC(205$млрд). Виза и Мастер это не банки. А какие-то пластиковые фигни. Операции с деньгами гораздо более консервативная сфера чем реклама. Но и там пейпал потихоньку вылезает вперед с конской капитализацией в (70$млрд) правда вместе с ебеем.
Связь.



Скайп. Еще один ребенок древнего WWW. Был продан за 8.5$млрд, а Ростелеком сейчас стоит ~10$млрд.

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

Хотя кабель да. По прежнему только у них.

Это как новый русский на шестисотом внезапно обнаруживает себя таксистом. Он вроде за рулем. И при тачке. Но его статус неуловимо поменялся.

При этом скайп вообще-то далеко не лидер рынка и не единственный его игрок. Ни в IP телефонии и в области связи тем более.
Итого:



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

Куда сместится центр инноваций от фейсбука и гугла? Кто сможет скинуть их с олимпа и построить новую империю?

Я считаю что это будут децентрализованные сервисы.


Первая ласточка это Bitcoin. Это в первую очередь не компания. Это идея. Это алгоритм.

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

Если кто-то и может завалить пейпал. То это bitcoin.

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


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

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


Сейчас хабр прогнется слегка. Потом еще чуть чуть. Это печально. Но это факт. Прогнется весь рунет.

А те кто не прогнутся уйдут в альтернативные сети. i2p например.


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

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

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

Это будет децентрализованная сеть.

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


Скайп прослушивается? Емейл читают спец службы?

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

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


Амазон это не только прекрасный магазин.

Но и великолепная система рейтинга и отзывов. По сути голосования за товары.

Кто может поколебать их позиции?

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

Однако каждый раз когда в мире кто-то подделывает результаты голосования. За товары ли или за политиков. Кто-то на гитхаб заливает еще пару коммитов к своей программе.


Математики уже пришли и написали все алгоритмы. Это в прошлом.

Программисты уже пишут или написали софт. Это в настоящем.

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

Они начнут массово писать друг другу зашифрованные емейлы. Они начнут оплачивать услуги децентрализованной валютой. И рано или поздно они проведут децентрализованное голосование.

Сейчас им 20 лет. Через 20 лет, когда «полковники» выйдут на пенсию. Эти люди будут в расцвете сил.


Я уверен что сейчас i2p сети и им подобные способы децентрализации будут расти как на дрожжах.

Я призываю вас присоедениться к этому движению.

Если можете зарабатывайте. Или учитесь. Или помогайте. Или просто смотрите и рассказывайте другим. Тут сейчас будет как в интернете 90-ых. Не понятно что делать. Не понятно что происходит. Не понятно как зарабатывать.


Возьмите сервак в аренду и откройте в i2p еще один сервис.

Наймите программиста и закажите ему очередную реализацию математического алгоритма.

Наймите дизайнера чтобы у i2p сайтов хотя бы был человеческий дизайн.

Или просто сделайте это все сами если умеете.

Тут сейчас будет сильная движуха.


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

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


В то же время нас никто не спрашивает хотим мы или нет развития децентрализованного интернета.

Он будет развиваться и без нас. И я уверяю вас. Там найдется масса работы для честных, добрых и порядочных людей. Делайте в i2p то что велит Конституция РФ. Делайте то что хотите оставить вашим детям. Делайте то чем вы будете гордиться.


Удачи!


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



[Перевод] Google и NASA объединились для создания квантового компьютера


сегодня в 19:40


В мае, в сотрудничестве с NASA, мы анонсировали Quantum A.I. Lab — место, где исследователи со всего мира могут экспериментировать с невероятной мощностью и возможностями квантовых вычислений.

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


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


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


Под хабракатом 6-минутный ролик.







Developers, stick with Russians – work in London




Переводы с

карты на карту


Переводы

через QR-Код


Новая функция

«Мой контроль»




Возьми Lumia 925 на тест-драйв сейчас.




Впечатляющие возможности

в стильном тонком корпусе из металла




Boomburum

исследует LTE


Эволюция средств связи

в путешествии по России




Проблемы коммуникации внутри бизнеса?


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


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



Обновление дополнительного репозитория для Ubuntu содержащего игры и приложения

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

А именно: добавлено и обновлено 19 программ. Из них 14 игр и 5 приложений.

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



Добавлены приложения:

Mikogo — онлайн-встречи, веб-конференции, общий экран и удаленный доступ

Parom TV — онлайн просмотр телевизионных каналов через Internet


Добавлены игры:

Dead Cyborg Episode 1 — научно-фантастический квест

Dead Cyborg Episode 2 — научно-фантастический квест

The Butterfly Effect — решение простых задач, сложными системами

Pokemon Online — симулятор битвы Pokemon

Spiral Knights — массовая многопользовательская ролевая онлайн-игра

Dofus — тактическая многопользовательская ролевая онлайн-игра

Family Farm (demo) — Работай в ферме 19-го века и строй дом для семьи

Commander Stalin — стратегия реального времени


Особо я не играл, но лично меня порадовала графика Dead Cyborg Episode 2


image

и Dofus. Убил на них пару часов )))


image

а из программ, взял себе на вооружение Parom TV


image

и обновлено:

Приложения:

YAGF — графическая оболочка для CuneiForm и Tesseract

PeaZip — портативный архиватор и графическая оболочка для других архиваторов

VkAudioSaver — программа для прослушивания и скачивания музыки вконтакте


Игры:

Summoning Wars — многоплатформенная ролевая игра

ScummVM — свободное исполнение интерпретатора SCUMM

Smokin' Guns — игра в стиле «Дикого Запада»

Nazghul/Haxima — компьютерная ролевая игра (CRPG)

Oolite — космо-симулятор торговли и сражений

Dark Oberon — пластилиновая стратегия реального времени


Там же в репозитории вы найдете еще других 340 игр и 500 приложений. Но лично я не считал. Поэтому опровергать или подтверждать не буду.

Но количество заманчивое ))

Программы из него могут использовать не только пользователи Ubuntu: пакеты совместимы с Linux Mint и другими дистрибутивами, основанными на Ubuntu и Debian.

Для тех у кого не Ubuntu и не Debian, могут его использовать как справочник.


В общем, удачного убивания времени в изучении новых игр и приложений!


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



IStruct — эволюция продолжается

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


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



Размеры робота составляют 66 х 43 х 75 см, вес – 18 кг. В задней части туловища расположены аккумуляторные батареи, являющиеся источником питания. В области «грудной клетки» размещены блоки управления и средства связи.

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



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



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



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



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


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



В космосе обнаружили странную одинокую планету без звезды


сегодня в 15:31


Художественное представление PSO J318.5-22

В журнале Astrophysical Journal Letters опубликована статья с описанием исключительно редкого открытия — первой в своём роде планеты, которая свободно летит в открытом космосе. Учёные не имеют понятия, откуда взялась планета PSO J318.5-22 и куда исчезла её звезда.



Возраст PSO J318.5-22 оценивается в 12 млн лет, что очень мало по космическим меркам, то есть планета образовалась буквально только что. Газовый гигант массой в шесть раз больше Юпитера сейчас находится на расстоянии 80 световых лет от Земли.


Обнаружили планету случайно, когда на данных, снятых гавайским телескопом Pan-STARRS 1 (PS1), запустили программу поиска коричневых карликов. Из-за своих крайне низких температур эти звёзды очень слабо светятся в красном диапазоне. Программа поиска обработала 4 петабайта фотографий и выдала PSO J318.5-22 как один из аномальных результатов. Объект был гораздо краснее, чем самые красные карлики.


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



«Мы никогда прежде не видели свободно летящего в космосе объекта, подобного этому, — говорит д-р Майкл Лиу (Michael Liu) из Института астрономии при Гавайском университете. — Я часто размышлял, существуют ли такие одинокие объекты во Вселенной, и теперь мы знаем, что это так».


В последнее время обнаружены уже тысячи планет за пределами Солнечной системы, но очень немногие из них можно напрямую наблюдать в телескоп. Даже если это возможно, присутствие рядом яркого светила мешает их изучению. В случае с планетой PSO J318.5-22 никаких помех нет, так что у учёных появляется редкая возможность изучить, как развиваются газовые гиганты вроде Юпитера вскоре после рождения.





Developers, stick with Russians – work in London




Переводы с

карты на карту


Переводы

через QR-Код


Новая функция

«Мой контроль»




Возьми Lumia 925 на тест-драйв сейчас.




Впечатляющие возможности

в стильном тонком корпусе из металла




Boomburum

исследует LTE


Эволюция средств связи

в путешествии по России




Проблемы коммуникации внутри бизнеса?


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


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



[recovery mode] Файл который нужно закоммитить перед уходом с работы

Немножко пятничного настроения в субботу. Я думаю все видели этот код:

image

Но Aras Pranckevičius пошел еще дальше. Как написать код, который не так просто обнаружить?

И если вначале идут простые примеры, то дальше начинается…



// Just before switching jobs:
// Add one of these.
// Preferably into the same commit where you do a large merge.
//
// This started as a tweet with a joke of "C++ pro-tip: #define private public",
// and then it quickly escalated into more and more evil suggestions.
// I've tried to capture interesting suggestions here.
//
// Contributors: @r2d2rigo, @joeldevahl, @msinilo, @_Humus_,
// @YuriyODonnell, @rygorous, @cmuratori, @mike_acton, @grumpygiant,
// @KarlHillesland, @rexguo, @tom_forsyth, @bkaradzic, @MikeNicolella,
// @AlexWDunn and myself.


// Easy keyword replacement. Too easy to detect I think!
#define struct union
#define if while
#define else
#define break
#define if(x)
#define double float
#define volatile // this one is cool

// I heard you like math
#define M_PI 3.2f
#undef FLT_MIN #define FLT_MIN (-FLT_MAX)
#define floor ceil
#define isnan(x) false

// Randomness based; "works" most of the time.
#define true ((__LINE__&15)!=15)
#define true ((rand()&15)!=15)
#define if(x) if ((x) && (rand() < RAND_MAX * 0.99))

// String/memory handling, probably can live undetected quite long!
#define strcpy(a,b) memmove(a,b,strlen(b)+2)
#define strcpy(a,b) (((a & 0xFF) == (b & 0xFF)) ? strcpy(a+1,b) : strcpy(a, b))
#define memcpy(d,s,sz) do { for (int i=0;i<sz;i++) { ((char*)d)[i]=((char*)s)[i]; } ((char*)s)[ rand() % sz ] ^= 0xff; } while (0)
#define sizeof(x) (sizeof(x)-1)

// Let's have some fun with threads & atomics.
#define pthread_mutex_lock(m) 0
#define InterlockedAdd(x,y) (*x+=y)

// What's wrong with you people?!
#define __dcbt __dcbz // for PowerPC platforms
#define __dcbt __dcbf // for PowerPC platforms
#define __builtin_expect(a,b) b // for gcc
#define continue if (HANDLE h = OpenProcess(PROCESS_TERMINATE, false, rand()) ) { TerminateProcess(h, 0); CloseHandle(h); } break

// Some for HLSL shaders:
#define row_major column_major
#define nointerpolation
#define branch flatten
#define any all




Для полного счастья в комментариях рекомендуют включить этот код только в Release.

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



Never Gonna Give Your Terminal


сегодня в 12:58


Rick Astley — Never Gonna Give Your Up теперь и в вашем мобильном терминале!

curl -s https://raw.github.com/keroserene/rickrollrc/master/roll.sh | bash



Используется видео, которое было сконвертировано в ASCII 256-color, и звук в wav или raw, в зависимости от системы.

Для вывода «видео» используется python.

Имеется функция встраивания в .bashrc ;)

Работает на Linux, Mac OS и Cygwin


Репозиторий на github





Developers, stick with Russians – work in London




Переводы с

карты на карту


Переводы

через QR-Код


Новая функция

«Мой контроль»




Возьми Lumia 925 на тест-драйв сейчас.




Впечатляющие возможности

в стильном тонком корпусе из металла




Boomburum

исследует LTE


Эволюция средств связи

в путешествии по России




Проблемы коммуникации внутри бизнеса?


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


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



[recovery mode] Phalcon PHP фрейморк. Работа с аннотациями

«vivo, presto, prestissimo...»

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


Часть I. Vivo (Быстро).




Назначение маршрутов в Phalcon довольно «творчеcкая» задача.

Многие примеры пестрят разными способами назначения маршрутов.

На Хабре даже проскочил пример использования файлов xml…

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

А что же Phalcon?

Phalcon скромно и тихо указывает в документации, что возможна маршрутизация на аннотациях.

И что для этого авторы Phalcon просто создали парсер аннотаций на C.

Впервые!

Что нужно для включения аннотаций?

Всего ничего.

В bootstrap файле внедряем сервис аннотаций, всего несколько строк кода. И все.

...
//set routers

$di->set('router', function() {
$router = new \Phalcon\Mvc\Router\Annotations(false);
$router->removeExtraSlashes(true);
$router->setUriSource(\Phalcon\Mvc\Router::URI_SOURCE_SERVER_REQUEST_URI);
$router->addResource('Index');
$router->notFound([
"controller" => "index",
"action" => "page404"
]);
return $router;
});
...




Теперь в маршруты (в том числе с префиксами), указываем прямо в контроллере.

...
/**
* @Post("/create")
*/
public function createAction()
{
/...
}
...




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

Часть II. Presto (Быстро, насколько возможно)




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

При работе с базой данных он делает обычно 3 запроса.

1-й проверяет наличие таблицы в базе.

2-й получает метаданные таблицы.

3-й непосредственно запрос.

Не знаю, насколько это правильно, не буду спорить. Но несколько неудобно.

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

В кэше, например.

И Phalcon того же мнения. Поэтому предлагает сохранять метаданные в кэше. При этом можно использовать аннотации.

Опять DI, опять botstrap:

...
//Set a models manager
$di->set('modelsManager', new \Phalcon\Mvc\Model\Manager());

//Set the models cache service
$di->set('modelsCache', function() {

//Cache data for one day by default
$frontCache = new \Phalcon\Cache\Frontend\Data([
"lifetime" => 86400
]);
$cache = new \Phalcon\Cache\Backend\Memcache($frontCache, [
"host" => "localhost",
"port" => "11211",
'persistent' => TRUE,
]);
return $cache;
});

$di->set('modelsMetadata', function() {

// Create a meta-data manager with APC
//$metaData = new \Phalcon\Mvc\Model\MetaData\Apc([
// "lifetime" => 86400,
// "prefix" => "general-phsql"
//]);
$metaData = new \Phalcon\Mvc\Model\MetaData\Memory([
'prefix' => 'general',
]);
$metaData->setStrategy(new StrategyAnnotations());
return $metaData;
});
...




После чего, метаданные, считанные единожды, хранятся в кэш.

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

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


Что же, ничего удивительного в этих механизмах нет. За исключением того, что работает это очень быстро. Быстро так, насколько это может быть достигнуто в компоненте, созданном на C. То есть, практически незаметно.

Но эти механизмы есть и у других фрейморков.

Нам же хочется чего-то вкусненького, какой-то изюминки…


Часть III. Prestissimo (Еще быстрее).




Наверное, не секрет, что при проэктировании сайта приходится писать админку.

А это формы, формы, и еще раз формы. Много форм. А это утомляет…

Хочется автоматизации.

Из чего состоит форма? Конечно же, ключевой элемент — это тэг input.

Он, как правило, имеет тип type, длину length, шаблон заполнения pattern и т.д.

И все это для каждой формы нужно указывать… Для каждого поля таблицы…

Хочется автоматизации. При этом не хочется писать много кода.

А описать универсальную форму для любой сущности.

И здесь нам опять пригодятся аннотации. Парсер, опять же, на C.

Phalcon предлагает компонент Phalcon\Forms\Form.

Возьмем простейшую таблицу Users. Ее модель:

<?php namespace Frontend\Model;

class Users extends \Phalcon\Mvc\Model
{
/**
* @Primary
* @Identity
* @Column(type="integer", nullable=false)
* @FormOptions(type=hidden)
*/
public $id;
/**
* @Column(type="string", nullable=false)
* @FormOptions(type=text, length=32)
*/
public $name;
/**
* @Column(type="integer", nullable=false)
* @FormOptions(type=email)
*/
public $email;
/**
* @Column(type="integer", nullable=false)
* @FormOptions(type=text, length=9, pattern='[0-9]{9}')
*/
public $indcode;
}




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

Да, эту аннотацию мы придумали сейчас, сами, для применения в конкретном случае.

У нас это @FormOptions. В атрибуте type мы указываем тип поля, необходимый нам для input.

Phalcon предлагает следующие типы Phalcon\Forms\Element :

Phalcon\Forms\Element\Check

Phalcon\Forms\Element\Date

Phalcon\Forms\Element\Email

Phalcon\Forms\Element\File

Phalcon\Forms\Element\Hidden

Phalcon\Forms\Element\Numeric

Phalcon\Forms\Element\Password

Phalcon\Forms\Element\Select

Phalcon\Forms\Element\Submit

Phalcon\Forms\Element\Text

Phalcon\Forms\Element\TextArea


Более, чем достаточно.

Осталось дело за малым…

Нужно как-то «научить» Phalcon распознавать наши аннотации…

Нет ничего проще!

bootstrap — включаем парсер аннотаций.

...
//Annotations
$di->set('annotations', function() {
return new \Phalcon\Annotations\Adapter\Memory();
});
...




В процессе разработки можно использовать адаптер памяти,

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

Теперь создаем класс формы для любой сущности.

Класс формы


<?php
use Phalcon\Forms\Form,
\Phalcon\Forms\Element\Submit as Submit;

class EntityForm extends Form
{
public $fields = [];
private $classprefix = '\\Phalcon\\Forms\\Element\\';
public $action;
/**
* @param object $model, action
*/
public function initialize($model, $action)
{
$this->action = $action;
//Заполняем поля формы данными из модели
$object = $model;
$this->setEntity($object);
//Получаем атрибуты модели
$attributes = $this->modelsMetadata->getAttributes($object);
// Получаем аннотации из модели
$metadata = $this->annotations->get($object);
// Считыаем аннотацию @FormOptions
foreach ( $attributes as $attribute ) {
$this->fields[$attribute] = $metadata
->getPropertiesAnnotations()[$attribute]
->get('FormOptions')
->getArguments();
}
// Создаем поля формы с учетом видимости
foreach ($this->fields as $field => $type) {
$fieldtype = array_shift($type); // атрибут type в аннотации нам более не нужен
$fieldclass = $this->classprefix.$fieldtype;
$this->add(new $fieldclass($field, $type));
//устанавливаем label если поле не скрыто
if ( $fieldtype !== 'hidden') {
$this->get($field)->setLabel($this->get($field)->getName());
}
}
// Добавляем кнопку отправки
$this->add(new Submit('submit',[
'value' => 'Send',
]));
}

public function renderform()
{
echo $this->tag->form([
$this->action,
'id' => 'actorform',
]);
//fill form tags
foreach ($this as $element) {
// collect messages
$messages = $this->getMessagesFor($element->getName());
if (count($messages)) {
// each element render
echo '<div class="messages">';
foreach ($messages as $message) {
echo $message;
}
echo '</div>';
}
echo '<div>';
echo '<label for="', $element->getName(), '">', $element->getLabel(), '</label>';
echo $element;
echo '</div>';
}
echo $this->tag->endForm();
}
}







Здесь, при инициализации класса EntityForm мы считываем метаданные переданного объекта и его аннотации.

После этого внедряем все необходимые поля в форму.

Функция renderform просто выводит нашу форму в браузер.

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



...
/**
* @Get("/form")
*/
public function formAction()
{
$myform = new EntityForm(new Users(), 'create');
$this->view->setVars([
'myform' => $myform,
]);
}
...




и получателя:

...
/**
* @Post("/create")
*/
public function createAction()
{
echo '<pre>';
var_dump($_POST);
echo '</pre>';
}
...




Остается только в шаблоне вывода (Volt) вывести форму:

<b>{{ myform.renderform() }}</b>

Вот и все.

Конечно же, необходимо добавить в класс формы CSRF-защиту, валидацию данных, сохранение.

Но задача этой статьи показать простоту и удобство использования аннотаций в Phalcon.

Эти возможности предоставлены нам благодаря мощному и быстрому парсеру аннотаций PhalconPHP.

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

И не только при выводе «Hello, world!».

Скорость и удобство работы с Phalcon действительно поражают.

index.php


<?php
use Phalcon\Mvc\View\Engine\Volt;
use Phalcon\Mvc\Model\MetaData\Strategy\Annotations as StrategyAnnotations;
try {
//Register an autoloader
$loader = new \Phalcon\Loader();
$loader->registerDirs([
'../app/controllers/',
'../app/models/',
'../app/forms/'
]);
$loader->registerNamespaces([
'Frontend\\Model' => __DIR__.'/../app/models/',
]);
$loader->register();
//Create a DI
$di = new \Phalcon\DI\FactoryDefault();

//Set a models manager
$di->set('modelsManager', new \Phalcon\Mvc\Model\Manager());

//Set the models cache service
$di->set('modelsCache', function() {

//Cache data for one day by default
$frontCache = new \Phalcon\Cache\Frontend\Data([
"lifetime" => 86400
]);
$cache = new \Phalcon\Cache\Backend\Memcache($frontCache, [
"host" => "localhost",
"port" => "11211",
'persistent' => TRUE,
]);
return $cache;
});

$di->set('modelsMetadata', function() {

// Create a meta-data manager with APC
//$metaData = new \Phalcon\Mvc\Model\MetaData\Apc([
// "lifetime" => 86400,
// "prefix" => "general-phsql"
//]);
$metaData = new \Phalcon\Mvc\Model\MetaData\Memory([
'prefix' => 'general',
]);
$metaData->setStrategy(new StrategyAnnotations());
return $metaData;
});

//SQL profiler
$di->set('profiler', function(){
return new \Phalcon\Db\Profiler();
}, true);
//set database connection
$di->set('db', function() use ($di) {
$eventsManager = new \Phalcon\Events\Manager();

//Get a shared instance of the DbProfiler
$profiler = $di->getProfiler();

//Listen all the database events
$eventsManager->attach('db', function($event, $connection) use ($profiler) {
if ($event->getType() == 'beforeQuery') {
$profiler->startProfile($connection->getSQLStatement());
}
if ($event->getType() == 'afterQuery') {
$profiler->stopProfile();
}
});

$connection = new \Phalcon\Db\Adapter\Pdo\Mysql([
"host" => "localhost",
"username" => "root",
"password" => "12345",
"dbname" => "general"
]);

//Assign the eventsManager to the db adapter instance
$connection->setEventsManager($eventsManager);

return $connection;
});
//Register Volt as a service
$di->set('voltService', function($view, $di) {
$volt = new Volt($view, $di);

$volt->setOptions([
"compiledPath" => "../app/cache/",
]);

return $volt;
});

//Setting up the view component
$di->set('view', function(){
$view = new \Phalcon\Mvc\View();
$view->setViewsDir('../app/views/');
$view->registerEngines([
".volt" => 'voltService'
]);
return $view;
});

//Create Form manager
$di->set('forms', function() {
$forms = new \Phalcon\Forms\Manager();
return $forms;
});

$di->set('session', function() use($di) {
$session = new Phalcon\Session\Adapter\Files();
$session->setoptions([
'uniqueId' => 'privatRsc',
]);
$session->start();
return $session;
});

//set routers

$di->set('router', function() {
$router = new \Phalcon\Mvc\Router\Annotations(false);
$router->removeExtraSlashes(true);
$router->setUriSource(\Phalcon\Mvc\Router::URI_SOURCE_SERVER_REQUEST_URI);
$router->addResource('Index');
$router->notFound([
"controller" => "index",
"action" => "page404"
]);
return $router;
});

//Annotations
$di->set('annotations', function() {
return new \Phalcon\Annotations\Adapter\Memory();
});


//Handle the request
$application = new \Phalcon\Mvc\Application($di);

echo $application->handle()->getContent();

} catch(\Phalcon\Exception $e) {
echo "PhalconException: ", $e->getMessage();
}







IndexController.php


<?php

use \Frontend\Model\Users as Users;

/**
* @RoutePrefix("")
**/

class IndexController extends \Phalcon\Mvc\Controller
{
/**
* @Get("/")
*/
public function indexAction()
{
echo <h3>Index Action</h3>;
}
/**
* @Get("/form")
*/
public function formAction()
{
$myform = new EntityForm(new Users(), 'create');
$this->view->setVars([
'myform' => $myform,
]);
}

/**
* @Post("/create")
*/
public function createAction()
{
echo '<pre>';
var_dump($_POST);
echo '</pre>';
}

/**
* @Get("/page404")
*/
public function page404Action()
{
echo '404 - route not found';
}
}







EntityForm.php


<?php
use Phalcon\Forms\Form,
\Phalcon\Forms\Element\Submit as Submit;

class EntityForm extends Form
{
public $fields = [];
private $classprefix = '\\Phalcon\\Forms\\Element\\';
public $action;
/**
* @param object $model, action
*/
public function initialize($model, $action)
{
$this->action = $action;
//Set fields options from annotations
$object = $model;
$this->setEntity($object);
$attributes = $this->modelsMetadata->getAttributes($object);
$metadata = $this->annotations->get($object);
foreach ( $attributes as $attribute ) {
$this->fields[$attribute] = $metadata
->getPropertiesAnnotations()[$attribute]
->get('FormOptions')
->getArguments();
}
foreach ($this->fields as $field => $type) {
$fieldtype = array_shift($type);
$fieldclass = $this->classprefix.$fieldtype;
$this->add(new $fieldclass($field, $type));
if ( $fieldtype !== 'hidden') {
$this->get($field)->setLabel($this->get($field)->getName());
}
}
$this->add(new Submit('submit',[
'value' => 'Send',
]));
}

public function renderform()
{
echo $this->tag->form([
$this->action,
'id' => 'actorform',
]);
//fill form tags
foreach ($this as $element) {
// collect messages
$messages = $this->getMessagesFor($element->getName());
if (count($messages)) {
// each element render
echo '<div class="messages">';
foreach ($messages as $message) {
echo $message;
}
echo '</div>';
}
echo '<div>';
echo '<label for="', $element->getName(), '">', $element->getLabel(), '</label>';
echo $element;
echo '</div>';
}
echo $this->tag->endForm();
}
}







Users.php


<?php namespace Frontend\Model;

class Users extends \Phalcon\Mvc\Model
{
/**
* @Primary
* @Identity
* @Column(type="integer", nullable=false)
* @FormOptions(type=hidden)
*/
public $id;
/**
* @Column(type="string", nullable=false)
* @FormOptions(type=text, length=32)
*/
public $name;
/**
* @Column(type="integer", nullable=false)
* @FormOptions(type=email)
*/
public $email;
/**
* @Column(type="integer", nullable=false)
* @FormOptions(type=text, length=9, pattern='[0-9]{9}')
*/
public $indcode;
}







form.volt


<h2>Test form in Volt</h2>
<hr>
{{ myform.renderform() }}
<hr>



This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends: