Как стать автором
Поиск
Написать публикацию
Обновить

Искусственная жизнь: Архитектура. Часть 1.

Про искусственную жизнь писалось уже довольно много и есть достаточное количество реализованных моделей. Но на мой взгляд они все уже достаточно старые и их подход не совсем удобен при разработке новых систем (хотя возможно я просто пока не нашел свежих реализаций). Порывшись в интернете и почитав разных статей на эту и смежные темы я представил себе как должна выглядеть современная модель.
Немного терминологии:
  • Объект — любая сущность в Мире.
  • Агент — объект, который может принимать решения и действовать в соответствии с принятыми решениями. Собственно вся Искусственная жизнь строится для исследования поведения агентов.
  • Представление — то, как видят/слышат/чувствуют объекты агенты.

Остальное вроде довольно стандартно и можно найти в интернете.
И так, начнем.
Мир.
Для упрощения интеграции новых моделей и поддержки существующих, мир должен быть отделим от агентов. Так же агенты должны знать о мире как можно меньше. Т.е. они не должны знать где они находятся (точные координаты), а должны только знать, что они видят. Мир имеет интерфейс, при помощи которого агенты получают всю необходимую им информацию (что видят/слышат и т.п.). Но мир об агентах тоже много знать не должен, поэтому агенты должны сами предоставлять миру интерфейс: видимый объект, слышимый объект. При помощи этого интерфейса и знания о место положении агента, мир, по требованию агента, выдает ему результаты работы методов тех объектов, которые находятся в определенном радиусе от данного агента. Таким образом миру все равно кого видит/слышит данный агент. Агент сам решает, что ему делать, не завязываясь на свои координаты и координаты других агентов/объектов. Также мир может говорить агенту о сложности доступа до каждого из видимых объектов, но этот параметр приблизителен.
Таким образом получим следующее разделение на зоны «влияния»:
image
За качество иллюстрации не бить — пока рисовать не умею).
Т.е. за принятие решения о дальнейших действиях отвечает агент. Затем мир реализует это действие (перемещение, атака, сбор и т.п.). Потом обновляет представление данного агента о мире и передает его агенту, который в свою очередь обновляет свое состояние, в зависимости от окружающей обстановки и снова решает, что же ему делать…

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

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

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

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

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

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

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

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

Прикладная футурология в отношении IT

Информационные технологии зародились в 60-х годах XX века и в 90-х годах – с началом инвестиций в сервисы Интернета – начался их бурный рост. Каковой продолжается и поныне, хотя и чуть более спокойными темпами. То есть, на сегодняшний день информационные технологии как самостоятельная технологическая отрасль не перевалили и 50-летний рубеж – информационные технологии молоды, очень молоды. Химия, к примеру, имеет за своими плечами более двухсот лет развития, физика – более ста.
Однако же, несмотря на более чем юный возраст, IT едва ли уже можно назвать младенцем – информационные технологии успели не только вылезти из мистически-алхимического состояния, но и сформироваться во вполне солидную технологическую отрасль с многомиллионными инвестициями. Экономика и финансы, производство, образование, социальные институты – всё разнообразие человеческой деятельности так или иначе испытывает потребность в получении, хранении и обработке информации, и именно информационные технологии напрямую призваны быть инструментом для эффективной работы с информацией. IT вошло в нашу жизнь и уходить оттуда в обозримом будущем не собирается.
Однако же насколько хорошо мы представляем себе это обозримое будущее? Кое-какие выводы и предложения на эту тему – ниже…

Читать дальше →

Lifecycle Security

В этой статье хочу рассказать о методике построения систем защиты информации под название Lifecycle Security. При помощи этой модели можно наглядно показать роль анализа рисков для создания корпоративной системы защиты информации. Методология разработана компанией Axent, впоследствии приобретенной Symantec.

Lifecycle Security – это обобщенная схема построения комплексной защиты компьютерной сети предприятия. Выполнение описываемого в ней набора процедур позволяет системно решать задачи, связанные с защитой информации, и дает возможность оценить эффект от затраченных средств и ресурсов. С этой точки зрения, идеология Lifecycle Security может быть противопоставлена тактике “точечных решений”, заключающейся в том, что все усилия сосредотачиваются на внедрении отдельных частных решений (например, межсетевых экранов или систем аутентификации пользователей по смарт-картам). Без предварительного анализа и планирования, подобная тактика может привести к появлению в компьютерной системе набора разрозненных продуктов, которые не стыкуются друг с другом и не позволяют решить проблемы предприятия в сфере информационной безопасности.
Читать дальше →

Безопасность интернет-банкинга для физических лиц

Добрый день, коллеги.

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

Что такое интернет банкинг, можете почитать здесь. Краткая выдержка из статьи:
«Основные преимущества интернет-банкинга
1. Возможность полного управления счетами и картами из любой точки, где есть Интернет.
2. Стоимость услуг ниже, чем в отделении банка, или вовсе отсутствует.
3. Мгновенное выполнение большинства операций.»

Всё ясно, понятно и до безобразия удобно.

Главная проблема с безопасностью в работе с интернет-банкингом кроется в том, что законы РФ не признают американский стандарт шифрования RSA, который широко используется банками. Стандарт RSA удобен тем, что его поддержка встроена в большинство современных ОС и прозрачно используется большинством браузеров.
Но единственно-правомочными стандартами на территории РФ являются на шифрование ГОСТ 28147-89 и на электронно-цифровую подпись (ЭЦП) ГОСТ Р 34.10-2001. Для того, чтобы поддержать данные стандарты необходимо установить крипто-провайдер на клиентский компьютер, который стоит денег. К сожалению, банки не хотят платить за эти лицензии.
Каждая операция над счетом должна быть подтверждена вашей подписью, а в случае с интернет-банкингом — ЭЦП. Я, к сожалению, не знаю ни одного банка в РФ, который бы предлагал ГОСТ ЭЦП своим клиентам (физ.лицам). Вместо этого, вас просят отправить SMS или создать ЭЦП по стандарту RSA. Эти действия не будут являться в суде доказательствами того, что именно вы совершили операцию над счетом.
Поле чудес для мошенников :)

Удачи.

PS. Информация о «честных» банках приветствуется. :)

CodeIgniter и xajax

Здравствуйте, представляю вольный перевод (поскольку не знаю английский -) инструкции по установке xajax в фреймворк CodeIgniter. Оригинал: wiki:CI с небольшими дополнениями от себя.

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

Итак, для того чтобы установить xAjax в CI необходимо:


Читать дальше →

Managed plugin для Native программы (на примере Winamp General Purpose plugin)

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

Однажды на моей работе появилась необходимость написать плагин к native программе. Вот там-то и понадобилась эта возможность — подключать managed dll к unmanaged модулю.

В этой статье я хочу рассмотреть пример простого плагина, написанного на C#, для проигрывателя Winamp.
Поехали

Centrix — управление всем и вся

Преамбула


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

Django: действия над группой объектов.

Не так давно, в джанго-админке появились Admin Actions (http://docs.djangoproject.com/en/dev/ref/contrib/admin/actions/#ref-contrib-admin-actions). О них я и хотел бы сегодня рассказать. В процессе записи такие действия я буду называть AdminAction.

Что это, и зачем оно мне нужно?



На самом деле необходимость такой вещи назрела уже давно. Допустим я хочу удалить все объекты определенной модели из админки (представим, что у меня их ~100 штук), не имея доступа к базе данных. Задача превращается в довольно муторную, и во всех нормальных продуктах давно уже можно пару раз жмакнуть по галочке «Выделить все» и удалить все выделенное за следующие пару кликов. Поэтому выкручивались джангисты как могли. А теперь все просто.

Смотрим как это просто




AdminAction это обычная функция, которая принимает три аргумента.
  1. Экземпляр ModelAdmin, к которому прикручено действие.
  2. HttpRequest объект, пришедший от пользователя.
  3. QuerySet выделенных объектов.
Представим, что у нас есть приложение testapp. В нем есть модель Post
  1. class Post(models.Model):
  2.     """ Post model. """
  3.    
  4.     title = models.CharField(max_length=25)
  5.     content = models.TextField()
  6.     is_draft = models.BooleanField(default=True)
  7.    
  8.     def __unicode__(self): return self.title


Boolean-поле is_draft сигнализирует о том, что запись черновик, и публиковать ее смысла нет. Сделаем свой AdminAction, который будет публиковать выделенные посты, т.е. ставить у постов is_draft=False.

Открываем admin.py и приводим его к такому виду:
  1. from django.contrib import admin
  2. from testapp.models import Post
  3.  
  4. def make_published(modeladmin, request, queryset):
  5.     """ Make all posts published. """
  6.     queryset.update(is_draft=False)
  7.     make_published.short_description = "Mark selected posts as published"
  8.  
  9. class PostAdmin(admin.ModelAdmin):
  10.     list_display = ('title', 'is_draft')
  11.     actions = [make_published]
  12.  
  13. admin.site.register(Post, PostAdmin)

Что мы тут видим. Видим функцию make_published которая как-раз принимает те три аргумента о которых я писал выше. В PostAdmin видим строчку actions = [make_published]. Эта строчка подключает наш AdminAction к PostAdmin. Внутри функции make_published мы просто вызываем метод update у QuerySet и устанавливаем для всех выделенных объектов is_draft=False. Вот и все. Запускаем приложение и смотрим как это работает:



Логичнее было-бы, плодить новые функции внутри класса PostAdmin, и не выносить их наружу, т.к. больше они нигде не используются. Это возможно, просто перепишем наш пример следующим образом:
  1. from django.contrib import admin
  2. from testapp.models import Post
  3.  
  4. class PostAdmin(admin.ModelAdmin):
  5.     list_display = ('title', 'is_draft')
  6.     actions = ['make_published']
  7.    
  8.     def make_published(self, request, queryset):
  9.         """ Make all posts published. """
  10.         queryset.update(is_draft=False)
  11.         make_published.short_description = "Mark selected posts as published"
  12.  
  13. admin.site.register(Post, PostAdmin)

Что изменилось? Ну во-первых функция make_published перекочевала в PostAdmin. Во-вторых вместо первого аргумента теперь self. И в третьих в actions она указана строкой. Запускаем, и проверяем, что все работает.

Необходимые вещи



Логично было бы показывать пользователю, сколько постов реально было опубликовано при действии. Для этого мы воспользуемся методом ModelAdmin.message_user (request, message).

Пишем:
  1. from django.contrib import admin
  2. from testapp.models import Post
  3.  
  4. class PostAdmin(admin.ModelAdmin):
  5.     list_display = ('title', 'is_draft')
  6.     actions = ['make_published']
  7.    
  8.     def make_published(self, request, queryset):
  9.         """ Make all posts published. """
  10.         count = queryset.filter(is_draft=True).update(is_draft=False)
  11.         self.message_user(request, '%s posts mark as published.' % count)
  12.         make_published.short_description = "Mark selected posts as published"
  13.  
  14. admin.site.register(Post, PostAdmin)

Проверяем:



Отлично. Все работает как нужно.

Интересные возможности



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

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

Включаем, выключаем



Мы рассмотрели возможность подключения AdminAction к определенному ModelAdmin. Но как могли заметить, стандартное действие удаляющее выделенные объекты, никуда при этом не делось. А что, если нам не нравится стандартный AdminAction, который позволяет удалять выделенные объекты? Это не проблема — AdminAction's можно активировать и деактивировать для всего сайта в целом. Например, чтобы выключить тот самый delete_selected, мы должны написать в admin.py:
  1. admin.site.disable_action('delete_selected')

После этого, мы можем включить действие delete_selected там, где оно нужно, просто указав в списке actions у определенного ModelAdmin. А чтобы активировать наше действие, например — make_all_good для всего сайта в целом, достаточно написать:
  1. admin.site.add_action(make_all_good, 'make_good_selected')

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

Чтобы выключить все действия для определенной ModelAdmin, достаточно присвоить action=None, внутри класса.

А если мы захотим иметь разный набор действий в зависимости от каких-либо условий, например от группы пользователя, то нам достаточно переопределить метод ModelAdmin.get_actions (self, request). Который возвращает список actions.

На мой взгляд — меганужная и ожидаемая фича.
______________________
Текст подготовлен в Хабра Редакторе от © SoftCoder.ru

Информационное пространство будущих систем

Вопросы:

) Как позволить размещать в системе информацию, независимо от ее типа?
) Какую модель разделения прав на доступ выбрать?
) Как разграничить доступ совокупностям пользователей или конкретным пользователям?
) Как любому пользователю управлять доступом к объектам, созданным им самим?

Предпосылки:

Подавляющие большинство современных систем управления содержимым сайтов(Content Management System) проповедуют разделение пользователей на администратора системы и прочих. В функции администратора входит настройка работы сайта:
— задание твердой структуры(разделов);
— присвоение разделу определенного типа содержимого(в блоге только сообщения, в форуме только темы);
— разграничение доступа к действиям над объектами разделов(матрицы доступа — добавить, изменить, просмотр).

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

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

Модель Свободной Социальной Системы(ССС)

Представим себе, что:

1) В системе существует набор возможных объектов, регламентирующих типы данных, которые можно размещать на сайте:
— сообщение;
— изображение;
— видео-ролик;
— файл общего типа;
— категория;
— приложение;
— другие виды.

2) Пользователь имеет возможность создавать свое собственное информационное пространство. Это означает свободную структуру его данных. Например, пользователь создает объект «Категория» и называет его «Блог», в составе этой категории он создает несколько объектов типа «Сообщение», в составе которых созадет объекты типа «видео-файл», «текст» и т.п. В общем случае количество объектов неограничено, что означает свободную структуру информационных объектов — свободное информационное пространство. Тип информации абсолютно неважен — каждый объект информации доступен для поиска на сайте через совокупность тегов. Например, видео-презентация системы будет, вероятно, иметь теги "'Свободная Социальная Система' ССС Презентация Видео".

3) Пользователь имеет возможность разграничивать доступ к действиям над объектами между группами пользователей, конкретными пользователями. Это означает, что в его информационнмо пространстве он создает правила поведения, создает группы пользователей — модель RBAC(role based access control). Например, в категорию «Фотографии» могут добавлять объекты типа «фотография» пользователи группы «друзья», а в блог добавлять объекты может только он и пользователь с именем «Маша».

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

Что дает ССС:

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

Модель Свободное Информационное Пространство(СИП)


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

Мои выводы:

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

Ручная работа — добавляем в нашу тему wordpress число фолловеров на твиттере (без плагинов)

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

1. Для начала копипастим следующий код в файл functions.php вашей активной вордпресс-темы:

function string_getInsertedString($long_string,$short_string,$is_html=false){
if($short_string>=strlen($long_string))return false;
$insertion_length=strlen($long_string)-strlen($short_string);
for($i=0;$i<strlen($short_string);++$i){
if($long_string[$i]!=$short_string[$i])break;
}
$inserted_string=substr($long_string,$i,$insertion_length);
if($is_html && $inserted_string[$insertion_length-1]=='<'){
$inserted_string='<'.substr($inserted_string,0,$insertion_length-1);
}
return $inserted_string;
}

function DOMElement_getOuterHTML($document,$element){
$html=$document->saveHTML();
$element->parentNode->removeChild($element);
$html2=$document->saveHTML();
return string_getInsertedString($html,$html2,true);
}

function getFollowers($username){
$x = file_get_contents("http://twitter.com/".$username);
$doc = new DomDocument;
@$doc->loadHTML($x);
$ele = $doc->getElementById('follower_count');
$innerHTML=preg_replace('/^<[^>]*>(.*)<[^>]*>$/',"\\1",DOMElement_getOuterHTML($doc,$ele));
return $innerHTML;
}


2. Теперь вставляем следующий код в нужном месте нужного файла темы (это может быть index.php, page.php, sidebar.php и иже с ними):

<?php echo getFollowers("vasily_pupkin")." followers"; ?>

Имя Василия, естественно, заменяем своим твиттеровским юзернэймом.

Вот и всё.

Бэкап в Linux.

Начальством однажды была поставлена задача организовать резервное копирование линуксового файл-сервера (учитывая наличие зеркального RAID — сомнительная задача, но тем не менее). На сервере нашем установлена мной Novell SLES 10. Я ожидал быстро справиться с этим вопросом посредством YaST Backup, но спустя пару дней понял, что это беспомощное, недоработанное и глючное чудище, о чем нам сообщает саппорт Novell на своем собственном форуме. Погуглив еще немного, понял, что большинство админов пишут для бэкапа свои скрипты и что какой-либо отлаженной фриварной утилиты либо нет, либо я плохо гуглил. В общем сел писать сам, и через два часа получил скрипт, помещенный под кат.

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

Читать дальше →

Проверка нахождения ссылки внутри тега noindex и наличия атрибута rel со значением nofollow

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

1) наличие ссылки;
2) не находится ли она внутри тега noindex;
3) не содержит ли тег a атрибут rel со значением nofollow.

В итоге получилась, приведенная ниже php функция checklink(), которая, возможно, кому-то пригодиться…

Взглянув недавно на скрипт, постарался вспомнить свой алгоритм определения не находится ли ссылка в noindex. Дело в том, что я попытался сделать так, чтобы скрипт не был поставлен в тупик даже в том случае, если в документе множество таких тегов, в том числе и вложенных… Решил резать документ по закрывающему noindex и проверять наличие ссылки в полученных кусках. Вроде работает;)

<?php

function checklink($page,$link) {

$err = array();

// Приводим передаваемые в функцию ссылки к единому виду (без 'http://')
if (preg_match("/^http:\/\//i",$link)) $link = preg_replace("/^http:\/\//","",$link);
// В случае отсутствия, добавляем 'http://' к ссылке на страницу
if (!preg_match("/^http:\/\//i",$page)) $page = "http://".$page;
// Экранируем спецсимволы...
$link = addslashes($link);
// ...слэши
if (preg_match("/\//",$link)) $link = preg_replace("/\//","\/",$link);

// Получаем html код страницы
$file = file_get_contents($page) or $err[] = "Не удалось загрузить страницу";

// А ссылка есть?
if (preg_match("/<a[\s\S]*href=[\"']*http:\/\/".$link."[\"'\s]+[^>]*>/i",$file) != FALSE && count($err) == 0) {

// Поиск rel="nofollow" в теге a -------------------
if (preg_match("/<a[\s\S]+href=[\"']*http:\/\/".$link."[^>]+nofollow[\s\S]*>/i",$file)) $err[] = "Найден rel=\"nofollow\"";
elseif (preg_match("/<a[\s\S]+rel=[\"']*nofollow[^>]*href=[\"']*http:\/\/".$link."[\"'\s]*[^>]*>/i",$file)) $err[] = "Найден rel=\"nofollow\"";
// ----------------------------------------------------

// Проверка нахождения внутри noindex ---------------
$nicount = 0;
$file = preg_split("/<\/noindex[^>]*>/",$file);
for ($i=0; $i<count($file); $i++) {
preg_match_all("/(<noindex[^>]*>)/i",$file[$i],$nimatches);
if (preg_match("/<a[\s\S]+href=[\"']*http:\/\/".$link."[\"'\s]*[^>]*>/i",$file[$i])) {
if (preg_match("/<noindex[^>]*>[\S\s]*href=[\"']*http:\/\/".$link."[\"']*/i",$file[$i]) || $nicount > $i) $err[] = "Возможно, ссылка находится в <noindex>";
}
$nicount += count($nimatches[1]);
}
// ----------------------------------------------------

} else $err[] = "Ссылка не найдена";

// Решаем, что возвращать
if (count($err) > 0) return $err;
else return FALSE;

}

// В качестве примера
$link = "http://php.net/manual/en/history.php.php";
$page = "http://ru.wikipedia.org/wiki/Php";
if ($test = checklink($page,$link)) print_r($test);
else echo "Все чисто";

?>

Знакомство brainfuck'a и питона со связкой PyQt4 и простеньким дебагером

Преамбула

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

Main
Вспомнил о существовании такова славного языка, как brainfuck, когда захотелось подумать логически, а высасывать математические задачи из пальца не хотелось. Но столкнулся с такой проблемой, как маленькое количество интерпретаторов и компиляторов под линукс. Переделывать Сишный код под линукс не получилось, а gcc матерился и буянил. Было решено написать свой интерпретатор, да не простой, а с дебагом, заодно использовать PyQt4, который и изучаю в данный момент. Справочным материалом послужили, переведенные статьи пользователем Amka (за что ему огромное спасибо) и riverbankcomputing.

Интерпретатор был сделан по каноном языка, с небольшим улучшением(или нет). В описании языка было установленно максимальное количество ячеек до 30000. В нижеописаном примере количество их динамически раширяется по мере необходимости и ограниченно лишь вашей оперативной памятью (или ограничением питона, если таковое имеется — не стал смотреть).
Читать дальше →

Первый шаг к уходу от табов (вкладок)

Желание поучаствовать в конкурсе «Придумай замену табам» от Mozilla Labs с нормальным концептом, вынуждает меня обратиться к аудитории с просьбой описать все ваши неудобства связанные с работой табов (вкладок)

предлагаю следующую схему для ваших ответов:
1. описание неудобства
2. решено ли это неудобство с помощью расширения ФФ? каким именно?
3. если нет, то что именно не решено?

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

Взгляд на пути развития программирования

Куда идем ?

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

Попробую разобрать все по полочкам. В принципе, объектно-ориентированное программирование (ООП), в том варианте, как оно существует в С++, начинает умирать. Попытаюсь обосновать свою мысль.
Сначала определимся с терминами. Набор данных (например, картинка, текст, цена, документ и пр.) не ОБЪЕКТЫ, а СУБЪЕКТЫ обработки. Существует накопленный достаточный багаж для обработки СУБЪЕКТОВ (структур данных), и в каком классе лежат эти инструменты не имеет особого значения. Что имеется в виду. Любой набор данных все равно состоит из элементарных данных, присутствующих в любом языке программирования и в любой базе данных, типа int, char, byte и т.д. – это все стандартный набор типов. Далее, с ними (с СУБЪЕКТАМИ) можно делать стандартный набор операций – сложение, вычитание, создание массивов, конкатенация строк и т.д. – стандартный набор операций (ИНТЕРФЕЙСЫ). Теперь, если взять группу СУБЪЕКТОВ и добавить группу ИНТЕРФЕЙСОВ, получим ОБЪЕКТ в смысле ООП. Другими словами:
СУБЪЕКТ – существительное;
ИНТЕРФЕЙС – глагол;
ОБЪЕКТ – сборник рассказов о СУБЪЕКТАХ;
таблица базы данных – массив СУБЪЕКТОВ,

Так почему же ООП не удовлетворяет, и чем дальше, тем больше?

Во-первых

Во-первых, наибольшую сложность разработки и сопровождения ПО представляет фрактальная природа данных. Простейший пример — не возможно в реляционных базах данных без потерь описать структуру данных для фильма. Сколько авторов? Сколько названий (на скольких языках)? Кто дублировал (или дубляжа нет, а вдруг появится в следующем году)? Актеры (один с фамилией и именем, другой ещё и с отчеством) и т. и п. Поэтому, основное содержание доработки ПО сводится к добавлению полей в классы (или таблицы баз данных) и исправлению тестов соответствующих полей.
Кстати, в Ruby on Rails эти два процесса более-менее автоматизированы – миграции и создание автоматически новых тестов для новых полей. Однако надо бы продумать (и добавить) и автоматизацию добавления ввода-вывода в HTML (вроде есть в Scaffold, но только создание для новой таблицы), или наоборот, удаления полей, тестов и т.д.

Во-вторых

Во-вторых, третья нормальная форма – не работает (когда-то вычитал в руководстве по «Ораклу»). Грубо говоря, третья нормальная форма – это вынесение за скобки (в отдельную таблицу (СПРАВОЧНИК), или массив) общей информации из главной таблицы с целью экономии. В основной таблице (или СУБЪЕКТЕ) вместо «Иван Иваныч Иванов» пишем «ID = 12345» (2 байта); а в СПРАВОЧНИКЕ есть строка «12345 = Иван Иваныч Иванов» (хоть килобайт).
Поскольку пользуется СПРАВОЧНИКОМ программа, а добавляет в СПРАВОЧНИК – человек, проверить полностью на корректность добавление невозможно. После трех ночей поисков вы определите, что «Иван Иванович Иванов» одно и тоже, что «Иван Иваныч Иванов», и сорвете подсчёт баланса в магазине, либо Вы обречены на пожизненную шлифовку программы.
Поэтому, чем больше библиотека проверки корректности введенных полей, тем круче пакет разработчика. Но боюсь, что скоро эти библиотеки станут основным содержанием профессиональных инструментов разработки ПО. Следовательно, такие библиотеки должны стать предметом отдельного бизнеса, как и графические пакеты.

В-третьих

В-третьих, глаголы (действия с данными, инструменты, одним словом ИНТЕРФЕЙСЫ) довольно скудны. В 90 % все дело сводится к рутинным «операциям» типа "+","-" и другая арифметика, операции с множествами (в том числе и REST из Ruby on Rails и других), да и все.
Для тех, кто не в курсе – REST – строгое ограничение на набор действий с данными, а именно, для HTML в Ruby on Rails:

GET – получение данных СУБЪЕКТА;
PUT – изменение данных СУБЪЕКТА;
POST – создание данных и нового СУБЪЕКТА;
DELETE – удаление данных и самого СУБЪЕКТА;

Совершенно также, как и в ООП, например так:

GET – чтение свойства или свойств ОБЪЕКТА;
PUT – запись свойства или свойств ОБЪЕКТА;
POST – конструктор ОБЪЕКТА;
DELETE – деструктор ОБЪЕКТА;

Так сколько же можно программировать? И что мы снова программируем? А программируем мы всего-навсего, операции ввода-вывода и перебора (отбора), и больше ничего, остальное уже все спрограммировано. Таким образом, определив состав данных и выбрав (именно выбрав, а не запрограммировав) методы определения корректности данных, достаточно одной строчки для генератора кода, который создаст 90% приложения (объектно-ориентированного), что и реализовано в Ruby on Rails и подобных продуктах.

В-четвёртых

В-четвёртых, в свете выше сказанного, почти любая значительная практическая задача не сводится к стандартному набору материалов (для программистов – данных) и инструментов, как монтаж гипсокартонных стенок. Примеров можно привести много. Жизнь требует постоянной изменчивости, набор данных невозможно застолбить. Мало того, наборы данных всё время норовят развалится на несколько разнотипных и даже порой несвязанных СУБЪЕКТОВ (например, как теги с атрибутами html развалились на теги хhtml и их стили в сss. Ведь сss можно использовать не только с хhtml и наоборот). Таким образом, идея объединить данные и код в устойчивую структуру порочна сама по себе. Хватит играть в классики!

Выводы

Если говорить о программировании, есть понятие — КОНТЕКСТ. Значительно более устойчивое, чем ОБЪЕКТ или СУБЪЕКТ. Правда, для его формулировки (может оказаться) 64 мегабайта маловато. Тем более для машинного перевода. Посмотрите, что происходит:

1С – бухгалтерия;
3D-Max – моделирование трёхмерных, мультипликация и т.д.;
Фотошоп – обработка изображений;
Autocad – конструирование;
PIСKAD – проэктирование печатных плат;
MathCad – математика;

Список бесконечен, все продукты несовместимы или плохо совместимы. Потому, что не сформулированы общие базовые ПОНЯТИЯ. Они совместимы только на уровне процессоров и Операционной системы. Если бы их разрабатывали на уровне ПОНЯТИЙ в КОНТЕКСТЕ, было бы легко перенести любой из этих продуктов в любую операционную систему, и открылся бы огромный рынок и исчез бы известный монополизм. Даёшь ПОНЯТИЯ, истинно «царский» путь в программировании!

Выводы из выводов

Дальше-больше. Пошла маниловщина. Почему нет (или мало) альтернатив в мире ОС? Потому что считается, что это очень сложная задача. Но её сложность состоит не в программировании. В свете выше изложенного, программировать надо всего (ура!) 4 функции на ПОНЯТИЕ (см. выше REST). Сложность – сформулировать ПОНЯТИЯ, а КОНТЕКСТ – это команды и быстродействие конкретного процессора (процессоров, ядер и т.д.) и регистры аппаратуры ввода-вывода (прерывания, видео, звук, USB и т.д.). КОНТЕКСТ залицензирован и стоит немалых денег. ПОНЯТИЯ – тоже, например проприетарные форматы типа NTFS. Заметьте, тот же NTFS позволяет что сделать с файлами:
Создание файла
Запись файла;
Чтение файла
Удаление файла.
И все.

Ничего не напоминает?

А что же мы? А мы программируем конечные автоматы. Ребра графа конечного автомата REST так и торчат из Rails. Добавляя функциональность, мы лишь запутываем дело. Любую задачу можно подвергнуть декомпозиции на REST-автоматы по ПОНЯТИЯМ, как материю на атомы. REST-автомат — это как 2-И-НЕ в схемотехнике.

Маниловщина в квадрате и в кубе

Следовательно, не за горами автоматическая разработка ОС для конкретного процессора. Насколько мне известно, автоматизация разработки процессоров уже давно практикуется. Правда нет широкой доступности ;).

Немного о бизнесе

Понятно, что золочёная электродрель (прекрасные продукты Adobe) для обработки, к примеру JPEG или MPEG-4 файлов, не всем доступна (private), но это же дело времени (например бесплатный код типа быстрого преобразования Фурье). И дело тут не в пиратстве. Кажется фирма Intel закрывала глаза на мелких несунов типа Стива Джобса. Зато теперь имеем Apple. Бесплатность Ruby on Rails и её практическая самодостаточность говорит о многом. Нет желающих платить (или изучать) одно и тоже много раз. И для этого Оксфорд, МТИ или МФТИ заканчивать не надо (печально, где ты студенческая молодость !). Достаточно для учебы, работы, вообще жизни, следовательно – и бизнеса (достаточно!) ADSL-доступа в Интернет.
А на чём же тогда зарабатывать новым поколениям программистов, когда всё вокруг автоматизировано? Да на продаже формулировки ПОНЯТИЙ, например: как объяснить машине, чем отличаются ПОНЯТИЯ «дерево – дуб» от «дуб – дерево» в КОНТЕКСТЕ русского языка кроме порядка букв. Может кто и заплатит за эти ПОНЯТИЯ. Но тут наверное уже маниловщина в экспоненте.

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

Удаленный доступ к файлам

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

Дано:
— среднестатистический офис с 8 компьютерами на WinXP и сервером на CentOS, выступающим в роли dhcp и файлопомойки.
— среднестатистический дом с ноутбуком.
— доступ в интернет с обеих сторон.

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

Читать дальше →

Анонимность серфинга в Google Chrome

В связи с выходом второй версии Google Chrome, ну во-первых поздравляю всех его пользователей, а во-вторых хочу рассказать одну важную вещь о этом чудо-браузере. Я думаю все знают, что данные о просмотренных страницах в Хроме отправляются в компанию Google, для статистики. Но если вам хочется свободы, или возможно у вас появился комплекс, а может и мания пресследования, есть способ, как обеспечить себе анонимный серфинг!

Пройдите по адресу C:\Documents and Settings\%userprofile%\Local Settings\Application Data\Google\Chrome\User Data\ Там вы найдете файл «Local State». Откройте его через всемогущий Блокнот :) Далее найдите в файле строку с «client_id», и удалите в ней идентифицирующую запись, заключенную в кавычки. В результате вы получите:
"client_id": " "
Аналогично редактируйте строку «client_id_timestamp». После этого сохраняем файл. Затем перейдите в свойства этого файла и установите атрибут «Только чтение». Запустите Хром и тут же закройте его. Благодаря атрибуту «Только чтение», браузер не сможет повторно записать идентифицирующую запись и создаст новый файл «Local State.tmp». Повторите вышеописанные действия с этим файлом(не забудьте про атрибут «Только чтение»).

Вот и все, можете спать спокойно :) Google про вас больше ничего не узнает.

JavaFX глазами Java разработчика

Начав месяца два назад знакомиться с JavaFX, уяснил, что к Java он имеет такое же примерно отношение, как и Java Script. Т.е. это вполне самостоятельный, хотя и не полнофункциональный язык.
Что я прав в своем заблуждении, подтвердил докладчик по JavaFx на Sun Tech Days. Рассказав мне в приватной (относительно) беседе, что скорее всего, FX код, который сейчас компилится в обычные Java классы, скорее всего в будущем будет компилиться в что-то свое. т.е. JavaFX будет удаляться от Java все сильнее.
Как програмист Java я столкнулся с некоторыми трудностями.

Как-то захотел я реализовать паттерн singleton, ан нет, полноценного сингелтона у нас не получиться никак.
т.е. единственное, что получиться более менее похожее это:
//*********************
var contentFactory: ContentFactory;
public function getInstance():ContentFactory {
if (contentFactory == null) {
contentFactory = ContentFactory {
};
}
return contentFactory;
}
public class ContentFactory {}

/********************************

но это не совсем сингелтон, т.к. мы всегда можем создать еще один объект ContentFactory таким образом.
var contFactory = ContentFactory{}
и никто нам не запретит это сделать.
Сделать же класс private можно, но тогда мы не сможем получить доступ к его статическому методу getInstance, даже если он public. Так что проблемма не имеет решения.
Еще одна проблемма в том, что в FX нет интерфейсов, только абстрактные классы, причем поля класса абстрактными не могут быть, только методы. Это, вкупе с отсутствием конструкторов, рождает еще одну проблему. Рассмотрим эту проблему на примере оздания GUI — основной задаче FX (предварительно надо сказать что все пользовательские графические элементы должны наследоваться от абстрактного класса CustomNode, который заставляет переопределять метод create():Node) итак:
мы хотим создавать графические объекты, построенные по единому шаблону, например, такому:image
т.е. они обязательно должны содержать какой-либо объект content (не обязательно listbox- любой) — слева вверху и btGroup — группу кнопок с нефиксированным размером ( в ней может быть 2,3, 7 кнопок, сколько угодно) — справа.
Начало понятно: мы создаем абстрактный класс, содержащий поля content и btGroup и унаследованный от CustomNode:

abstract public class MyAbstractNode extends CustomNode{
var content: Node;
var btGroup: SwingButton[];
override function create():Node{.....};
function setLayout(): Void{
//размещаем объекты, как нам надо
}
}

можно было обойтись и без setLayout(), задав положение объектов в методе create(), но если у нас сложные объекты, то лучше разнести эти задачи, чтобы не перегружать create(), хотя личное дело каждого.
как заставить выполняться метод setLayout, если нет конструкторов?
самый простой путь — помещаем его в create()
а можно по другому- в FX классе можно создавать блок init{...}, который будет выполняться при каждом создании элемента класса, поэтому помещаем setLayout() в init:

abstract public class MyAbstractNode extends CustomNode{
var content: Node;
var btGroup: SwingButton[];
init{ setLayout()};
override function create():Node{.....};
function setLayout(): Void{/*размещаем объекты, как нам надо*/};
}

но если мы создадим класс NodeA, унаследованный от MyAbstractNode, ничто не заставит нас инициализировать поля btGroup и content., т.к. абстрактных полей в JavaFX нет, т.е. мы можем создать объект NodeA так:var node = NodeA{}
что можно сделать? тут нам на выручку приходят абстрактные методы и блок инит. модифицированный MyAbstractNode:

//*************************
abstract public class MyAbstractNode extends CustomNode{
var content: Node;
var btGroup: SwingButton[];
init{
setLayout();
content = initContent();
btGroup = initBtGroup();
};
abstract function initContent():Node;
abstract function initBtGroup():SwingButton[];
override function create():Node{.....};
function setLayout(): Void{/*размещаем объекты, как нам надо*/};
}
//*************************

все. Кстати, можно было и без init{...}:
//*************************
abstract public class MyAbstractNode extends CustomNode{
var content: Node = initContent();
var btGroup: SwingButton[] = initBtGroup();
abstract function initContent():Node;
abstract function initBtGroup():SwingButton[];
override function create():Node{
setLayout();
.....};
function setLayout(): Void{/*размещаем объекты, как нам надо*/};
}
//*************************


теперь при создании класса, унаследованного от MyAbstractNode, мы обязанны будем переопределить методы инициализации объектов, иначе будет ошибка компиляции.
public class NodeA extends MyAbstractNode{
override function initContent(): Node{.....};
override function initBtGroup(): SwingButton[]{.....};
}

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

это все, спасибо за внимание.

А не спеть ли мне песню…

Бывают такие случаи, когда сайт должен начать издавать звуки. Банальный пример — сайт артиста или музыкальной группы. Недавно и передо мной была поставлена задача добавить музыкальной оформление к одному сайту. В ходе её решения я нашел замечательный инструмент — Soundmanager 2, информацией о котором и решил поделиться с хабросообществом.
Soundmanager 2 — это набор JavaScript + Flash, подключив которые вы сможете:
  • Загружать и проигрывать музыку, ставить на паузу, мьютить и управлять громкостью посредством Javascript;
  • Следить за такими событиями, как начало и окончание проигрывания, окончание загрузки файла и многими другими;
  • Получать из mp3 файлов данные ID3v1 и ID3v2 тегов;
  • И многое другое.
Заинтересовались? Читайте дальше

Nested Tables в Oracle для чайников.

Cегодня таки пришлось столкнуться с nested tables в Oracle.
Началось всё безобидно… я не знал, что такое nested tables.

chuma
мозг себе взорвал
чтобы так искать по идее нужно чтобы в табличке было поле типа pic_search_word_tabtype например. Зачем оно нужно, или когда заполняется, не могу понять…
Артур
ты почитал что такое nested table? =)
chuma
а
chuma
сейчас почитаю

И я полез читать. Такого левелапа не получал уже месяца 2 ^_^ Зато теперь знаю и умею, может пригодится когда-нибудь) Смысл этих табличек — хранить в поле записи таблицы, а не значения.

Делается оно вот так:
1. Создаем свой тип. у меня тип назывался NEAR_WORD_TABTYPE и представлял собой список строк:

CREATE TYPE «SERVICE».«NEAR_WORD_TABTYPE» AS
TABLE OF VARCHAR2(200)

2. Задача — хранить в записях таблицы список строк. Для этого добавляем поле такого типа в таблицу.

ALTER TABLE NEAR_ADDRESS
ADD (S_WORDS NEAR_WORD_TABTYPE) NESTED TABLE S_WORDS STORE AS S_WORDS_TABLE;

т.е. добавили поле с именем S_WORDS моего пользовательского типа, и указали что имя таблицы (ведь мы типа храним в записи еще 1 таблицу) будет S_WORDS_TABLE. Мне это имя потом не пригодилось

3. Как запихивать туда значения? Делается это в 2 этапа. Изначально это поле NULL и добавить туда ничего нельзя. Чтобы было можно — надо при вставке нормальной записи указать, что в поле S_WORDS таки будет список. При этом вставляется пустой список:

INSERT INTO NEAR_ADDRESS (S_WORDS, ID)
VALUES
(NEAR_WORD_TABTYPE(), 500);
commit;

4. Теперь можно вставить что-нибудь в нашу таблицу в таблице.

INSERT INTO
THE
(
SELECT S_WORDS FROM NEAR_ADDRESS A WHERE ID = 500
)
VALUES ('hello');

при этом внимание! запрос внутри THE() должен возвращать четко одну запись. А вставить туда можно сколько угодно значений, выполняя предыдущий запрос с THE() несколько раз.

5. Проверяем, получилось ли у нас вставить туда что-нибудь?

SELECT * FROM NEAR_ADDRESS, TABLE(CAST(S_WORDS AS NEAR_WORD_TABTYPE)) WHERE ID= 500;

Запрос вернет столько строк, сколько записей в поле S_WORDS, в поле param_value (само прибьется) будут значения.

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

Стоит хотя бы попробовать, а применения в голову полезу во время первого перекура)