Обновить

PyQt4 — простейшее рисование

Отрисовка текста


#!/usr/bin/python

# drawtext.py

import sys
from PyQt4 import QtGui, QtCore

class DrawText(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)

self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Draw Text')

self.text = u'Hello from Python'

def paintEvent(self, event):
paint = QtGui.QPainter()
paint.begin(self)
paint.setPen(QtGui.QColor(168, 34, 3))
paint.setFont(QtGui.QFont('Decorative', 10))
paint.drawText(event.rect(), QtCore.Qt.AlignCenter, self.text)
paint.end()

app = QtGui.QApplication(sys.argv)
dt = DrawText()
dt.show()
app.exec_()


Текст выровнен по вертикали и горизонтали.

def paintEvent(self, event):
Для прорисовки создали функцию

paint = QtGui.QPainter()
paint.begin(self)
...
paint.end()

Класс QPainter отвечает за всю прорисовку. Все рисование должно быть между методами begin() и end().

paint.setPen(QtGui.QColor(168, 34, 3))
paint.setFont(QtGui.QFont('Decorative', 10))

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

paint.drawText(event.rect(), QtCore.Qt.AlignCenter, self.text)
Метод drawText() рисует текст в окне
image

Рисование точек


#!/usr/bin/python

# points.py

import sys, random
from PyQt4 import QtGui, QtCore

class Points(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)

self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Points')

def paintEvent(self, event):
paint = QtGui.QPainter()
paint.begin(self)
paint.setPen(QtCore.Qt.red)
size = self.size()
for i in range(1000):
x = random.randint(1, size.width()-1)
y = random.randint(1, size.height()-1)
paint.drawPoint(x, y)
paint.end()

app = QtGui.QApplication(sys.argv)
dt = Points()
dt.show()
app.exec_()

В нашем примере мы рисуем случайно 1000 красных точек.

paint.setPen(QtCore.Qt.red)
Устанавливаем перо в красный цвет

size = self.size()
Генерируется каждый раз, когда мы изменяем размер окна

paint.drawPoint(x, y)
Рисуем точки методом drawPoint()
image

Цвета


Цвета мы можем задать в виде значения RGB (в диапозоне от 0 до 255), в шестнадцатеричной системе, ну или же в RGBA (red, green, blue, alpha). Значение alpha 255 определяет полную не прозрачность, 0 для полной прозрачности.

#!/usr/bin/python

# colors.py

import sys, random
from PyQt4 import QtGui, QtCore

class Colors(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)

self.setGeometry(300, 300, 350, 280)
self.setWindowTitle('Colors')

def paintEvent(self, event):
paint = QtGui.QPainter()
paint.begin(self)

color = QtGui.QColor(0, 0, 0)
color.setNamedColor('#d4d4d4')
paint.setPen(color)

paint.setBrush(QtGui.QColor(255, 0, 0, 80))
paint.drawRect(10, 15, 90, 60)

paint.setBrush(QtGui.QColor(255, 0, 0, 160))
paint.drawRect(130, 15, 90, 60)

paint.setBrush(QtGui.QColor(255, 0, 0, 255))
paint.drawRect(250, 15, 90, 60)

paint.setBrush(QtGui.QColor(10, 163, 2, 55))
paint.drawRect(10, 105, 90, 60)

paint.setBrush(QtGui.QColor(160, 100, 0, 255))
paint.drawRect(130, 105, 90, 60)

paint.setBrush(QtGui.QColor(60, 100, 60, 255))
paint.drawRect(250, 105, 90, 60)

paint.setBrush(QtGui.QColor(50, 50, 50, 255))
paint.drawRect(10, 195, 90, 60)

paint.setBrush(QtGui.QColor(50, 150, 50, 255))
paint.drawRect(130, 195, 90, 60)

paint.setBrush(QtGui.QColor(223, 135, 19, 255))
paint.drawRect(250, 195, 90, 60)

paint.end()

app = QtGui.QApplication(sys.argv)
dt = Colors()
dt.show()
app.exec_()


image

color = QtGui.QColor(0, 0, 0)
color.setNamedColor('#d4d4d4')

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

paint.setBrush(QtGui.QColor(255, 0, 0, 80));
paint.drawRect(10, 15, 90, 60)

Здесь определяем кисть, и рисуем прямоугольник. Метод drawRect () рисует прямоугольник, первые два параметра координаты X и Y, третий и четвертый — ширина и высота.

Линии


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

#!/usr/bin/python

# penstyles.py

import sys
from PyQt4 import QtGui, QtCore

class PenStyles(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)

self.setGeometry(300, 300, 280, 270)
self.setWindowTitle('penstyles')

def paintEvent(self, event):
paint = QtGui.QPainter()

paint.begin(self)

pen = QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine)

paint.setPen(pen)
paint.drawLine(20, 40, 250, 40)

pen.setStyle(QtCore.Qt.DashLine)
paint.setPen(pen)
paint.drawLine(20, 80, 250, 80)

pen.setStyle(QtCore.Qt.DashDotLine)
paint.setPen(pen)
paint.drawLine(20, 120, 250, 120)

pen.setStyle(QtCore.Qt.DotLine)
paint.setPen(pen)
paint.drawLine(20, 160, 250, 160)

pen.setStyle(QtCore.Qt.DashDotDotLine)
paint.setPen(pen)
paint.drawLine(20, 200, 250, 200)

pen.setStyle(QtCore.Qt.CustomDashLine)
pen.setDashPattern([1, 4, 5, 4])
paint.setPen(pen)
paint.drawLine(20, 240, 250, 240)

paint.end()

app = QtGui.QApplication(sys.argv)
dt = PenStyles()
dt.show()
app.exec_()


В этом примере мы рисуем шесть линий. Линии проведены в шести различных стилях.

pen = QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine)
Создали QPen объект, цвет черный, толщина 2, QtCore.Qt.SolidLine является одним из предопределенных стилей пера.

pen.setStyle(QtCore.Qt.CustomDashLine)
pen.setDashPattern([1, 4, 5, 4])
paint.setPen(pen)

Здесь мы определяем пользовательский стиль пера. Список цифр определяет стиль пера. В нашем примере. Чем больше число тем больше пространство или тире. У нас: 1px заполнено, 4px пустота, 5px заполнено, 4px пустота, и т.д.
image

QBrush


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

#!/usr/bin/python

# brushes.py

import sys
from PyQt4 import QtGui, QtCore

class Brushes(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)

self.setGeometry(300, 300, 355, 280)
self.setWindowTitle('Brushes')

def paintEvent(self, event):
paint = QtGui.QPainter()

paint.begin(self)

brush = QtGui.QBrush(QtCore.Qt.SolidPattern)
paint.setBrush(brush)
paint.drawRect(10, 15, 90, 60)

brush.setStyle(QtCore.Qt.Dense1Pattern)
paint.setBrush(brush)
paint.drawRect(130, 15, 90, 60)

brush.setStyle(QtCore.Qt.Dense2Pattern)
paint.setBrush(brush)
paint.drawRect(250, 15, 90, 60)

brush.setStyle(QtCore.Qt.Dense3Pattern)
paint.setBrush(brush)
paint.drawRect(10, 105, 90, 60)

brush.setStyle(QtCore.Qt.DiagCrossPattern)
paint.setBrush(brush)
paint.drawRect(10, 105, 90, 60)

brush.setStyle(QtCore.Qt.Dense5Pattern)
paint.setBrush(brush)
paint.drawRect(130, 105, 90, 60)

brush.setStyle(QtCore.Qt.Dense6Pattern)
paint.setBrush(brush)
paint.drawRect(250, 105, 90, 60)

brush.setStyle(QtCore.Qt.HorPattern)
paint.setBrush(brush)
paint.drawRect(10, 195, 90, 60)

brush.setStyle(QtCore.Qt.VerPattern)
paint.setBrush(brush)
paint.drawRect(130, 195, 90, 60)

brush.setStyle(QtCore.Qt.BDiagPattern)
paint.setBrush(brush)
paint.drawRect(250, 195, 90, 60)

paint.end()

app = QtGui.QApplication(sys.argv)
dt = Brushes()
dt.show()
app.exec_()

В нашем примере мы рисуем 6 различных прямоугольников.

brush = QtGui.QBrush(QtCore.Qt.SolidPattern)
paint.setBrush(brush)
paint.drawRect(10, 15, 90, 60)


Определяем тип кисти, и рисуем прямоугольник, с помощью метода drawRect()
image

Антиспам для Skype

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

Нет — будет. На сайте обнаружился какой-никакой, а ассортимент wrapper'ов к API. Выбор пал на Python, ибо ничего масштабного не требовалось, а «import antigravity» только радовало. В процессе отладки скрипта было замечено несколько косяков в API. Оные были заботливо подпёрты костылями. Итак:

import Skype4Py
from time import sleep
skype = Skype4Py.Skype()
TRYING = 1
TEXT = {
¬'QUESTION':"Hello. It's antispam bot. Answer, 2+2=? One figure, please. You have %i trying." % (TRYING),
¬'ANSWER':"4",
¬'WIN':"Right. I'll write you soon.",
¬'AGAIN':"Try one more time.",
¬'FAIL':"Autoignoring.",
¬'INSTANT_BAN':"Autoignoring due to banned word in the authorization request or in the name."
}
BANNED = {
¬'WORDS':("http", "www"),
¬'NAMES':("")
}
HIDE_MESSAGES_AFTER_WRONG_ANSWER = True # True may cause loss of the new answers
REFRESH_DELAY = 30 # in seconds
GET_NAME_DELAY = 1.5
queue = {}

def answer_received(msg, status):
¬username = msg._GetSender()._GetHandle()
¬if username in queue.keys():
¬¬if status==Skype4Py.cmsReceived:
¬¬¬if msg._GetBody()!=TEXT['ANSWER']:
¬¬¬¬if HIDE_MESSAGES_AFTER_WRONG_ANSWER:
¬¬¬¬¬skype.UnregisterEventHandler('MessageStatus', answer_received)
¬¬¬¬¬for eachMsg in msg._GetChat()._GetRecentMessages():
¬¬¬¬¬¬try:
¬¬¬¬¬¬¬eachMsg.MarkAsSeen()
¬¬¬¬¬¬except:
¬¬¬¬¬¬¬continue
¬¬¬¬¬skype.RegisterEventHandler('MessageStatus', answer_received)
¬¬¬¬queue[username] = queue[username]-1
¬¬¬¬if queue[username]:
¬¬¬¬¬skype.SendMessage(username, TEXT['AGAIN'])
¬¬¬¬¬return
¬¬¬¬else:
¬¬¬¬¬del queue[username]
¬¬¬¬¬skype.SendMessage(username, TEXT['FAIL'])
¬¬¬¬¬msg._GetSender()._SetIsBlocked(True)
¬¬¬else:
¬¬¬¬del queue[username]
¬¬¬¬skype.SendMessage(username, TEXT['WIN'])
¬¬¬if len(queue)==0:
¬¬¬¬skype.UnregisterEventHandler('MessageStatus', answer_received)

def hasBanned(txtstr, target):
¬for word in BANNED[target]:
¬¬if word in txtstr:
¬¬¬return True
¬return False

def auth_received(from_user):
¬newUsers = skype._GetUsersWaitingAuthorization()
¬if not newUsers:
¬¬for key in queue.keys():
¬¬¬del queue[key]
¬¬return
¬for user in newUsers:
¬¬username = user._GetHandle()
¬¬if not (username in queue.keys()):
¬¬¬if TRYING < 1:
¬¬¬¬skype.SendMessage(username, TEXT['FAIL'])
¬¬¬¬user._SetIsBlocked(True)
¬¬¬¬continue
¬¬¬if hasBanned(user._GetReceivedAuthRequest(), 'WORDS'):
¬¬¬¬skype.SendMessage(username, TEXT['INSTANT_BAN'])
¬¬¬¬user._SetIsBlocked(True)
¬¬¬¬continue
¬¬¬skype.RegisterEventHandler('MessageStatus', answer_received)
¬¬¬skype.SendMessage(username, TEXT['QUESTION'])
¬¬¬queue[username] = TRYING
¬¬¬sleep(GET_NAME_DELAY)
¬¬¬if hasBanned(user._GetFullName(), 'NAMES'): # Skype's bug: full name is available only after message sending
¬¬¬¬del queue[username]
¬¬¬¬skype.SendMessage(username, TEXT['INSTANT_BAN'])
¬¬¬¬user._SetIsBlocked(True)
¬¬¬¬if len(queue)==0:
¬¬¬¬¬skype.UnregisterEventHandler('MessageStatus', answer_received)
¬¬¬¬continue

skype.RegisterEventHandler('UserAuthorizationRequestReceived', auth_received)
# В принципе следующий цикл не обязателен, но тогда при перезапуске скайпа придётся перезапускать и скрипт. И именно в такой последовательности.
while True:
¬skype.Attach()
¬auth_received(None)
¬sleep(REFRESH_DELAY)


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

P.S. К счастью, волна спама давно поутихла, но вдруг кому-то пригодится.

CodeIgniter — роутинг через базу данных

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

Принцип действия следующий:
1. В базе содержатся alias'ы страниц, к примеру '/it' и '/it/articles'. Последнему соответствует определенный контроллер и метод, допустим 'pages' и 'showList' соответственно.
2. Роутинг CodeIgniter'a смотрит куда обращаться по query_string или path_info. Эту строку мы и будем сравнивать с alias'ом в базе.
3. После сравнения, мы находим самое большое вхождение имеющейся строки. Допустим, если мы введем в строке '/it/test', то результатом будет алиас '/it', а если '/it/articles/param1' — '/it/articles' (все это делается одним запросом)
4. Для передачи параметров, мы из исходной строки удаляем alias, тем самым получается остаток от URI и являющийся параметрами, которые передадутся методу.

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

Манифест к хабросообществу, как самой многочисленной аудитории IT специалистов в России

Мы стоим на пороге новых открытий, технологий и продуктов для широкого использования. Информационные технологии, компьютеры, телефоны, портативные устройства, навигаторы стали частью нашей жизни и мы используем их каждый день в нашей деятельности. Область IT самая быстроразвивающаяся во всем мире. Посмотрите, что было достигнуто за поледние 20 лет, 10 лет и 5 лет. Каждый год появляются новые технологии, устройства, продукты, которые делают будущее уже сейчас. И благодаря кому это происходит? Благодаря нам, конечно! За всем этим стоят специалисты IT, которые претворяют, порой, даже самые невероятные идеи в жизнь. В 80-х годах началась эра информационных компьютеров. Они прошли путь от огромных вычислительных машин, но с маленькой мощностью для научных институтов до высокопроизводительных систем и портативных устройств, которые умещаются в вашем кармане и востребованы обывателями. Скорость обмена информацией возрасла на порядки за эти годы.
Настало время для нового продукта, который пройдет похожий путь. Роботы. Роботы от программируемых сварочных аппаратов на автозаводах, до неуклюжих конструкций, иммитирующих походку животных и действия человека, вперед к полноценным роботам, которые будут нужны каждому человеку в каждом доме. Роботов, которые не выходят из строя от воды, слабых источников питания, роботов, способных принимать решения на основе прошлого опыта, роботов, которые будут помогать человеку в его повседневных делах.
Читать дальше →

VDPAU или смотрим HD фильмы на Ubuntu

image

Тут товарищ hosco говорит, цитирую:
«Блин, перешёл бы на Линукс (именно этот дистрибутив покорил меня своей простотой в красоте и красотой в простоте), если бы не прошлый печальный опыт с 7-кой. Всё вроде заработало «из коробки», но отказывалось нормально проигрываться HD-видео. После волшебных пассов напильником оно проигрывалось, но после оказалось, что не передаётся звук по HDMI. Полазив по форумам, выяснилось, что сотворить звук по HDMI сродни только человеку с возможностями Нео :) Это мы хотели из Acer Revo сделать медиа-центр. Надеюсь 8-ка избавит многих от никчёмных страданий :)»
Тема — habrahabr.ru/blogs/ubuntu/75144

Ведь хочется помочь этому конкретному человеку, да и чёрт возьми многим другим, но инвайта мне никто не даёт, так что… =ъ «помогите люди добрые, сами мы не местные». Авансом я вам расскажу, как прикрутить VDPAU к SMplayer и XBMC Media Center, для комфортного просмотра HD видео.

Заранее предупреждаю, в линуксе я всего 2 года, так что многие советы могут показаться чересчур… ламерскими? Что я в связи с этим предлагаю, дорогие мои профи, если во-время прочтения у вас что-то и где-то сильно засвербит, кожа покраснеет, а глаза начнут выползать из орбит — не мучайте себя, перестаньте читать немедленно.
По-моему для %username% важнее то, что в итоге всё будет работать, а не трушность подхода. Всё проверенно на себе, на Acer Aspire Revo 3600.
С другой стороны, я должным образом приму любую критику и советы, дабы придать данному мануалу должный вид.

Со вступлением разобрались, и так начнём.
Читать дальше →

Избавляемся от лишних #include'ов

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

Поэтому у меня возникла идея написать скрипт, который автоматически будет проверять зависимости от хедеров и убирать ненужные. Сканируя все входные файлы, он последовательно пытается убрать все строки, содержащие подстроку "#include", и скомпилировать результат. Если make завершается успешно, скрипт считает, что удалённая строка не нужна.

Скрипт написан на bash и требует от исходников двух вещей:
1) Программа собирается с помощью утилиты make.
2) В данный момент программа успешно компилируется.

#!/bin/bash

function del {
FILE=$1
TEMP_FILE=$FILE".tmp"
BAK_FILE=$FILE".bak"
LINE=$2

echo -n "$LINE..." | tr -d \\r
grep -v "$LINE" "$FILE" > $TEMP_FILE 2>/dev/null
cp $FILE $BAK_FILE
cp $TEMP_FILE $FILE

#cat $FILE
sleep 1
touch -m $FILE
make >/dev/null 2>&1 && echo "YES" || ( cp $BAK_FILE $FILE; echo "NO" )
rm -rf $BAK_FILE $TEMP_FILE
}

function check {
FILE=$1
echo "---------- $FILE ----------"

grep '#include' $FILE | \
while read LINE;
do
del $FILE "$LINE"
done
}

until [ -z "$1" ]
do
check $1
shift
done


Скрипт иногда может работать не совсем корректно:
1) Если A.cpp напрямую зависит от B.h и C.h, а B.h в свою очередь зависит от C.h, то скрипт удалит зависимость A.cpp от C.h. Это не всегда правильно, т.к. зависимость B.h от C.h может измениться без участия A.cpp. Причём такие зависимости могут меняться при смене платформы или компилятора.
2) Если в хедерах есть некая хитрая макроподстановка. Например, файл, содержащий только строки типа #define USE_SOME_FEATURE. Без них программа будет компилироваться, но будет компилироваться не так, как нам хочется.

Также скрипт работает довольно долго: (количество директив #inlcude + время компиляции одного модуля + время линковки) секунд. Это вызвано необходимостью добавления в скрипт строки «Sleep 1», т.к. make проверяет время изменения файлов с точностью до секунды, а частота запуска make больше одного раза в секунду.

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

Критика статьи OpenCL. Практика.

Здравствуйте хабрики! Очень смешное у вас название.

Во-первых, автор ошибается, когда пишет: «Далее выберем устройство (у меня в системе оно всего одно, но на будущее пусть в нашей программе используется устройство с максимальным числом FLOPS).» т.к. он забыл то, что OCL может работать как с GPU, так и с CPU.

Ещё вот эта выделенная жирным шрифтом фраза должна быть помещена гораздо выше, не к оператору oclLoadProgSource, а к oclGetMaxFlopsDev: "ВНИМАНИЕ!!! oclLoadProgSource — не является функцией OpenCL API, а находятся в вспомогательной библиотеке, поставляемой вместе с Nvidia Computing SDK.". Почему? Да потому, что в oclGetMaxFlopsDev я сразу встретился с проблемой, что нет такой функции! А вот узнал, что оказывается она всё таки есть, через пару абзацев.

К предыдущему абзацу. Почему собственно не приведено имя библеотеки? Или её надо самому найти, пользуюсь экстросенсурными способностими? Чтоб не искали — это oclUtils.cpp.

Нужна ссылка на драйверы. Как же без этого? Я ввёл первую строчку и бабах, оказалось, что в системе нет OpenCL.dll.

Статья, конечно, является едвали не единственным описанием OpenCL на практике и на русском, но надо её немного подправить.

Скверная проблема — изменение размера шрифтов в Chrome; или как не ослепнуть за большим разрешением.

Наверняка не я один сталкивался с проблемой изменения размера шрифта фиксированной величины в google chrome на windows. А проблема ведь для многих может быть насущной, вот например у меня 20 дюймовый монитор с разрешением 1680х1050, размер пикселя соответственно небольшой, и читать текст 13ого размера очень неудобно, да что там, ослепнуть можно! «мне бы по-больше, а?»

В общем нашел 2 способа, как это можно ее решить:
первый — в папке C:\Users\имя пользователя\AppData\Local\Google\Chrome\User Data\Default или вместо Users может быть Documents and Settings есть файл Preferences, открываете его блокнотом. В самом конце находите

«webkit»: {
«webprefs»: {
«default_fixed_font_size»: 17,
«default_font_size»: 18,
«fixed_font_family»: «Bitstream Vera Sans Mono»,
«inspector_settings»: «lastActivePanel:string:elements\n»,
«minimum_font_size»: 14,
«minimum_logical_font_siz»: 14,
«sansserif_font_family»: «Times New Roman»,
«serif_font_family»: «Arial»,
«standard_font_is_serif»: false,
«text_areas_are_resizable»: true,
«uses_universal_detector»: true

изменяете там цифры, сохраняете — все)

ps: может быть вариант(у меня так и было), что там следующее:

«webkit»: {
«webprefs»: {
«uses_universal_detector»: true

если будет именно это, то приведите к виду указанному выше(возможно придется удалить строчку «uses_universal_detector»: true

так, это был первый способ.

Теперь способ №2:
Ставите последнюю DEV(тестовую) версию, скачать ее можно отсюда
Там появляется поддержка так называемых расширений. Добавляется это расширение
Теперь при запуске хрома, можете изменить размер страниц в нижней левой части экрана(прямо над пуском). Это изменение будет действовать до закрытия браузера. Т.е. до закрытия браузера все страницы будут открываться именно в том масштабе, который выбрали в этом расширении. При новом запуске придется выбрать заново.

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

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

Так же имеется расширение 125% zoom, которое изменяет навсегда(ну почти) размер страниц, думаю понятно насколько. Нашел я его тут, в осуждении какой-то статьи в разделе хрома.

кстати на линуксе всего этого копро нету — не удивительно кстати

Искусственный Интеллект AND or VS. Человек?!

Трудно что-либо предвидеть, а уж особенно будущее. Нильс Бор.

Ну начнем, пожалуй, не с будущего, а с прошлого. Что вам приходит на ум, когда вы видите дату 29 августа 1997 года? Ничего? А если я сообщу вам, что в этот день в Мичигане из-за неэкономичности была закрыта старейшая в США АЭС, а на Украине открылся конвент фантастов «ФАНКОН-97»? Опять на ум ничего не приходит? А если подобрать ассоциации к этим событиям: атомная энергия, научная фантастика? Опять мимо? Ну ладно, не буду больше вас томить – дело в том, что именно 29 августа 1997 года, согласно знаменитой тетралогии о терминаторах, суперкомпьютер Министерства Обороны США SkyNet, спроектированный Cyberdyne Systems Corporation для управления системой противоракетной обороны США, обретает сознание и начинают разворачиваться события, которые нам хорошо известны.

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

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

История человечества в основном – история идей. Герберт Уэллс.

Первые исследования, относящиеся к проблемам искусственного интеллекта, были предприняты почти сразу же после появления вычислительных машин. Само название новой науки возникло в конце 60-х годов XX века, а в 1969 году в Вашингтоне (США) состоялась первая Всемирная конференция по искусственному интеллекту.

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

Вроде бы цели благие – создать интеллект на подобие человеческого, отправить его вместо себя на работу, а самому за заработанные роботом с ИИ деньги нежиться на золотистом пляже Черного моря (а кто сказал, что робот будет зарабатывать больше вас?). При этом такого робота можно задействовать в опасных сферах деятельности человека, обезопасив тем самым жизнь этого самого человека. Хочу заметить, что речь не идет о современных роботах, типа сапера и т.п., где не требуется применение интеллекта. Речь идет о роботах с ИИ, которые бы смогли заменить на «боевом» посту человека, а главное – его интеллектуальную деятельность вкупе с функциональными возможностями человека, а, может быть, даже превосходящими его. Самый типичный пример, на мой взгляд, робот-полицейский. Вот только тут сразу появляется много нюансов. Один из них – можно ли считать робота с ИИ особой формой жизни, только не на основе углерода, а, скажем, кремния и, пожалуй, главный вопрос – можно ли считать его личностью. Если утвердительно ответить на этот вопрос (а для этого есть все основания), то мы углубимся еще дальше – какое право мы имеем эксплуатировать роботов с ИИ, рисковать их жизнями и т.д. Ведь даже у животных в современном цивилизованном обществе есть права. На практике выходит создание нового рабовладельческого строя (не зря говорят, что история развивается по спирали), а в таком строе, как мы знаем из уроков истории, нередко случались восстания.

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

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

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

Но это все кажется нам далеким будущим, а что же ждет нас в ближайшем? Специалисты одной из самых влиятельных в мире аналитических компаний в области технологических исследований и консалтинга — Gartner — сделали ряд предсказаний на предстоящее десятилетие, касающихся информационных технологий. Так, к 2015 году 40% нынешних должностей в сфере IT заменят средства автоматизации. Организаторы бизнес-процессов смогут менять потоки работ в них при помощи графических интерфейсов без участия специалистов IT-отдела. Это, конечно, приведет к отмиранию многих современных должностей.

Какой же из всего этого можно сделать вывод? А вот какой – cам по себе ИИ, как и большинство изобретений человечества, не хорош и не плох. Самое важное – осознание человеком ответственности за использование своих изобретений перед окружающим миром. Мне кажется, что хотя и лаконичный, но достаточно емкий вывод, жаль только, что не мой, но хорошо, что и не искусственного интеллекта :)

З. Ы. Наслаждайтесь общением с людьми и мыслями друг друга. Возможно, скоро за нас будут думать ДРУГИЕ (звучит финальная мелодия из Терминатора 2).

nnCron — в бой идут одни старики

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

В жизни всегда есть место для творчества — на сцене появляется nnCron. Что это такое? Если сказать, что это планировщик или твикер — это будет верно, но не до конца. nnCron — это швейцарский нож для управления ресурсами вашего компьютера. При своём мало-размере возможности его впечатляют. Лучше об этом почитать на сайте производителя.

Минимум, что он умеет — это запускать приложения по времени (sheduler), при этом синтаксис команд совместим с Unix crontab. Максимум — это встроеный скриптовый язык. При этом не обязательно для добавления задачи писать макрос, у nnCron есть и GUI, через который можно управлять заданиями в привычной для многих форме. По мне, так все остальные твикеры и шедуллеры для виндовз — идут строем в ресайкл бин.

А теперь — слайды :)

Назначаю горячую клавишу <Ctrl+F12> на запуск The Bat

#( Bat-start
AsLoggedUser
WatchHotKey: “^{F12}”
Action:
StartIn: “C:\Program Files\The Bat!”
ShowNormal NormalPriority
START-APP: C:\Program Files\The Bat!\thebat.exe
)#


Назначаю горячую клавишу <Ctrl+F11> на запуск Mozilla Firefox
Тут немного интереснее — если Firefox уже запущен, то nnCron не будет запускать копию, а сделает окно Firefox активным.

#( Firefox-start
AsLoggedUser
WatchHotKey: “^{F11}”
Action:
PROC-EXIST: “firefox.exe”
IF
WIN-ACTIVATE: “/.*firefox/i”
ELSE
StartIn: “C:\Program Files\Mozilla Firefox”
ShowNormal NormalPriority
START-APP: C:\Program Files\Mozilla Firefox\firefox.exe
THEN
)#


Поработал — отдохни.

Назначаю хоткеи <Ctrl+F10> на воспроизведение DVD (используется Mplayer) и <Ctrl+F9> — на воспроизведение mp3 (Winamp).
При запуске Winamp, неплохо было бы, чтобы он сразу стартовал проигрывание трека, я надеялся нагуглить какие-нибудь параметры командной строки для оного, но нашёл это — плагин AutoPlay. Всяко неплохо, даже ещё интереснее. И наконец, чтобы уж до конца довести идею “once-click”, — при запуске DVD будем убивать Winamp, зачем — обьяснять не буду.

#( Mplayer-DVD-autoplay
AsLoggedUser
WatchHotKey: “^{F10}”
Action:
StartIn: “C:\mplayer”
ShowNormal HighPriority
KILL: “mplayer.exe”
KILL: “winamp.exe”
START-APP: C:\mplayer\mplayer.exe dvd://0 -dvd-device e: -fs
)#


#( Winamp-start
AsLoggedUser
WatchHotKey: “^{F9}”
Action:
StartIn: “C:\Program Files\Winamp”
ShowNormal NormalPriority
KILL: “winamp.exe”
START-APP: C:\Program Files\Winamp\winamp.exe
)#


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

image

Домен.РФ, кириллица в URL и кодировки: добро пожаловать в ад.

Здравствуйте. Итак, я человек которому очень не нравится английский язык, принципиально. А потому, я, ещё задолго до придумывания сильными и умными мира сего домена.РФ, загорелся целью сделать себе сайт с кириллическими ЧПУ. Сайт уже существует, хотя и параллельно дорабатывается до вменяемого состояния.

Но вот началось регистрация доменов.РФ, и скоро, надо полагать, там появятся первые сайты. И скорее всего владельцы кириллического домена захотят чтобы url из сайта выглядел не так: http://домен.рф/news/my_otkrylis/, а вот так: http://домен.рф/новости/мы_открылись/
А так, как я начала реализовывать нечто подобное, то думаю что мой опыт будет многим полезен. Особенно программистам и SEO специалистам — именно для них тут будет много весёлых, занимательных открытий, после которых у некоторых наверняка возникнет желание сделать что-то нехорошее с теми массовиками-затейниками, которые всё это придумали. Если бы я сам знал, что меня ждёт, никогда не стал бы так извращаться и сделал бы всё на латинице.

Итак, поехали.

ЧПУ и сам кириллический URL.


Как обстоит дело с обычными GET запросами вроде ?категория=новости&статья=мы_открылись, я не знаю, но думаю с тут проблем быть не должно. А вот если вы захотите сделать ЧПУ, то боюсь, что придётся вам его делать в коде самой страницы, а не через mod_rewrite, ибо последний кириллицу не понимает. В .htaccess крякозяблы приходят, вместо русских букв. И подружить .htaccess с кириллицей у меня так и не получилось (если кому-то это удастся, то пожалуйста, дайте знать как).

Но тут есть ещё один подводный камень. У меня весь сайт в кодировке cp1251. А от браузеров URL всегда приходит в UTF-8 кодировке, независимо от ОС и браузера. Но в случае, если вы будете делать header(), то тут прежде всего нужно будет перекодировать в юникод. Ибо после header() заголовок посылается уже в той кодировке, которая была в переданной строке, а не в юникоде.
И тут главное чтобы ie6 наконец уже окончательно канул в бездну, так как он, после header`а, в адресной строке отображает крякозяблы. Благо это только его баг, во всех остальных браузерах вроде всё работает как нужно.

Однако, боюсь, что дальше этого пойти не удастся. Я имею ввиду то, что внутренние ссылки не поддерживают кириллицу как минимум в ie6-8 (учитывая что ie занимает всё-таки лидирующие позиции среди пользователей интернета, да и пользоваться этими доменами будут в основном люди не всегда знающие о существовании других браузеров, кроме ie, то думаю что именно на этот браузер нужно ориентироваться в первую очередь).
Т.е. если есть ссылка с name="якорь", то при переходе с http://домен.рф/новости, на http://домен.рф/новости#якорь — страница перезагрузится. Так что клиентов, которые хотят чтобы на их свежекупленном домене.РФ не было латинских символов в принципе, придётся убеждать в необходимости латиницы в якорях.
Но это ещё цветочки, а ягодки пойдут дальше…

Кириллические URL`ы, поисковики и системы размещения рекламы.


А вот здесь начинается настоящий ад. Тут очень многое зависит от настроек сервера. Например, при работе сайта в сети обнаружились очень интересные особенности. А именно, при индексации некоторыми поисковиками и система размещения рекламы страниц с кириллическими URL`ами, сервер им выдавал 406 код ошибки, хотя сам скрипт всё обрабатывал как нужно, делал нужные sql запросы и получал всё необходимое содержимое. И оказалось, что в utf-8 кодировке URL приходит только от браузеров, а все остальные шлют запросы в том виде, в каком им хочется. В частности была и такая проблема с Яндексом. Вот часть ответа из службы поддержки по поводу причины такого явления:
Проверка показывает, что сервер формирует данный код ответа на запрос
документов в типе text/html. То есть, по какой-то причине, сервер, отдавая
text/html, считает, что он не может быть обработан роботом и формирует ответ
406 Not Acceptable.
Браузерам (например FireFox) отдается страница с кодом 200, так как они
отправляют запрос, который предполагает, что сервер может вернуть любой тип
контента, если нет возможности вернуть text/html, application/xhtml+xml или
application/xml (Accept:
text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8).


Собственно после этого, я плюнул и решил перевести всё-таки все страницы сайта utf-8 кодировку. Но, как ни странно, это не помогло. А дело оказалось в том, что для правильного ответа сервера нужно не просто, чтобы сами ссылки были в юникоде, но и чтобы они были закодированы через urlencode(), иначе — всё равно 406 ошибка. В этом отношении меня порадовал только лишь Google. Ему всегда возвращается 200 код, в какой бы кодировке что не находилось.

Таким образом, для того, чтобы некоторые избранные могли проиндексировать вашу страницу, нужно чтобы они переходили по URL находящемуся в utf-8 кодировке и обработанному через urlencode(). Строка в win-1251 и urlencode() тоже не пройдёт, только юникод.

При этом обработать ссылки через urlencode() не всегда легко так легко. К примеру, что будет, если контент сайта внутри заполняется кем-то, кто не знает вообще про кодировки ничего и он создаст просто обычную внутреннюю ссылку вида href="/новости"? Более того, получается что таким системам и людям нужно подсовывать разные ссылки — людям обычные ссылки, а роботам ссылки после urlencode()? Да и с и с точки зрения того же Яндекса, будут ли одинаковыми ссылки http://домен.рф/новости и http://домен.рф/%D0%BD%D0%BE%D0%B2%D0%BE%D1%81%D1%82%D0%B8? Не уверен. А при публикации ссылок на внешних ресурсах как быть?
Лично я решил эту проблему так: у меня просто определяется, что за клиент передо мной: из «чёрного списка», в котором все те, кому 406-ая ошибка когда надо и не надо возвращается, или нет. В первом случае при выводе в меню ссылки обрабатываются через urlencode() и весь основной контент страницы так же пропускается через функцию, которая ищет внутренние ссылки, и, если находит, то заменяет их на обработанные в urlencode().

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

Ну и на последок ещё одна «нехорошесть».


Ну вот всё описанное выше вы решили, и запустили сайт в сеть. Поставили счетчики статистики и вроде бы все рады, пока клиент не просмотрит статистику через cpannel и не увидит примерно следующее: /\xd0\xbd\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x81\xd1\x82\xd0\xb8. Или на топ.мейл увидит всё те же самые URL`ы, закодированные через urlencode(). И вот попробуйте ему в таком случае объяснить, что вы тут не властны, и что это вовсе не то, что вы хотите скрыть от него кто и какие страницы сайта посещал. А ведь согласитесь, в таком представлении даже сведущему человеку не сразу понять что это за такое, а уж простому обывателю и подавно.

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

P.S. Этой мой первый пост на хабре. Извиняюсь, если что-то запостил не так и спасибо всем вам за прочтение. Я буду очень получить инвайт за этот пост)))

BlueJ или ООП для начинающих.

Hello Habrapeople!

Поискав информацию о BlueJ в блогах Хабра, на свое удивление, ничего не обнаружил. Как впрочем и удивлен незначительному количеству статей о JAVA. Значит есть возможность о чем рассказать.:)

image

BlueJ.


Программа была разработана университетами Deakin University (Мельбурн, Австралия) и University of Kent (Canterbury, Великобритания) на основе имеющейся среды Blue, как часть исследовательского проекта по обучению ООП начинающих программистов при поддержке Sun Microsystems. Иными словами, BlueJ(голубая сойка) — это среда программирования для студентов, начинающих изучать JAVA и основы ООП. Особый акцент был сделан на визуализацию и методы взаимодействия для создания интерактивной среды, обеспечивающей понимание того, как все устроено. Программа классифицируется как freeware, работает в любой операционной системе и скачать ее можно здесь.

image

Главный экран показывает структуру классов разрабатываемого приложения в графическом виде (на UML-подобной диаграмме), а объекты можно создавать и тестировать интерактивно. Подобная интерактивность совместно с ясным, простым интерфейсом пользователя позволяет легко экспериментировать с разрабатываемыми объектами. Концепции объектно-ориентированной разработки (классы, объекты, сообщение через вызов методов) интерактивны и наглядно представлены в интерфейсе. Подробнее о причинах использования зарубежными университетами BlueJ и тонкостях интерфейса можно прочитать тут.

Редактируемая линия с тултипом в Google Maps

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

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

Суть.
Итак, в процессе создания столкнулся с необходимостью отображать линии между объек-тами. При этом линии должны отвечать нескольким требованиям:
  1. Возможность редактировать с сохранением в базу.
  2. У каждой линии должна быть подпись. Т.к. линий было очень много, пришлось подписи сделать всплывающими.
  3. При редактировании линии должна быть возможность добавлять точки и изломы.

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

Исходник: labeledline2.js

Пример: тут

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


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

C#. Argument null validator

Как избавиться от строковых констант при проверке аргументов на null, то есть избавиться от хард-кодед констант. Имеем пример:

    private static void FillStringBuilderCommon(StringBuilder stringBuilder, String stringArgument)
    {
      if (stringBuilder == null)
      {
        throw new ArgumentNullException("stringBuilder");      }
      if (stringArgument == null)
      {
        throw new ArgumentNullException("stringArgument");
      }

      stringBuilder.Append(stringArgument);
    }

* This source code was highlighted with Source Code Highlighter
.



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

  static class Extensions
  {
    public static string GetName<TResult>(this Expression<Func<TResult>> expression)
    {
      return ((MemberExpression)expression.Body).Member.Name;
    }
  }

* This source code was highlighted with Source Code Highlighter
.
Что привело к следующему варианту функции проверки аргумента на null

    public static void NullValidate1<TResult>(Expression<Func<TResult>> argumentExpresion)
      where TResult : class
    {
      if (argumentExpresion.Compile()() == null)
      {
        throw new ArgumentNullException(argumentExpresion.GetName());
      }
    }

* This source code was highlighted with Source Code Highlighter
.

Жутко медленная вещь получилась, я вам скажу, что естественно меня не уcтраивало ни коим образом. Данная функция позволяет, кратко и понятно записать вызов валидации, например:

      Tools.NullValidate1(() => stringBuilder);

* This source code was highlighted with Source Code Highlighter
.


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

    [DebuggerStepThrough]
    public static void NullValidate2<TResult>(Expression<Func<TResult>> argumentExpresion, TResult argument)
      where TResult : class
    {
      if (argument == null)
      {
        throw new ArgumentNullException(argumentExpresion.GetName());
      }
    }

* This source code was highlighted with Source Code Highlighter
.


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

      Tools.NullValidate1(() => stringBuilder, stringBuilder);

* This source code was highlighted with Source Code Highlighter
.


Как показали тесты на произволительность, потери были значительными, на порядки. Вся проблема заключалась в первом аргументе. Объяснять «почему?» думаю не надо.
В итоге пришел к заключительному виду, коим пользуюсь сейчас:

    [DebuggerStepThrough]
    public static void NullValidate<TResult>(TResult argument, Func<Expression<Func<TResult>>> nameRetreiver)
      where TResult : class
    {
      if (argument == null)
      {
        throw new ArgumentNullException(nameRetreiver().GetName());
      }
    }

* This source code was highlighted with Source Code Highlighter
.

Вызывается так:

Tools.NullValidate(stringBuilder, () => (() => stringBuilder));

Таким образом тестовая функция в целом выглядит следующим образом:

    private static void FillStringBuilderExpression(StringBuilder stringBuilder, String stringArgument)
    {
      Tools.NullValidate(stringArgument, () => (() => stringArgument));
      Tools.NullValidate(stringBuilder, () => (() => stringBuilder));

      stringBuilder.Append(stringArgument);
    }

* This source code was highlighted with Source Code Highlighter
.


Результаты перформанс теста:

[FillStringBuilderCommon] StringBuilder length: 3000000
[FillStringBuilderCommon]: 00:00:00.0532751
[FillStringBuilderExpression2] StringBuilder length: 3000000
[FillStringBuilderExpression2]: 00:00:07.2346404
[FillStringBuilderExpression] StringBuilder length: 3000000
[FillStringBuilderExpression]: 00:00:00.1308366
Press any key to exit...


Код теста:

   static void Main(string[] args)
    {
      MeasureFunc((sb, arg) => FillStringBuilderCommon(sb, arg));

      MeasureFunc((sb, arg) => FillStringBuilderExpression2(sb, arg));
      MeasureFunc((sb, arg) => FillStringBuilderExpression(sb, arg));

      Console.WriteLine("Press any key to exit...");
      Console.Read();
    }

    private static void MeasureFunc(Expression<Action<StringBuilder, string>> functionExpression)
    {
      const uint limit = 1000000;
      string title = string.Format("[{0}]", ((MethodCallExpression)functionExpression.Body).Method.Name);

      Action<StringBuilder, string> function = functionExpression.Compile();

      StringBuilder stringBuilder = new StringBuilder();
      String stringArgument = "saa";
      
      Stopwatch stopwatch = new Stopwatch();
      stopwatch.Start();

      uint index = 0;
      while (index++ < limit)
      {
        function(stringBuilder, stringArgument);
      }

      stopwatch.Stop();

      Console.WriteLine(title + " StringBuilder length: " + stringBuilder.Length);
      Console.WriteLine(title + ": " + stopwatch.Elapsed);
    }

* This source code was highlighted with Source Code Highlighter
.


С уважением, Александр.

Составление технического задания (ТЗ) на сайт с использованием ГОСТ.

image

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

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

Размышления об ООП в Javascript.

С некоторых пор я озаботился поиском интересных технологий веб-разработки, в частности довольно плотно занялся изучением специфических решений на JavaScript + HTML + Java/Flash(ActionScript). Именно так я, кстати, и забрёл на хабрахабр.

Я нашёл много интересного, но обо всём по порядку. Я обнаружил, что практически каждая уважающая себя библиотека в той или иной форме пытается реализовать некое подобие классового подхода (или «классовой парадигмы», если так понятнее) на JS — это и MooTools, и qooxdoo, и Prototype (хотя это и мало соотносится с его названием) и многие другие. Я мог бы поспорить с тем, что ООП в «классическом» (т.е. классовом) его понимании так уж необходим в JS — сильно развитые возможности функционального программирования в этом языке могут быть гораздо эффективнее — но раз классический подход реализуется, значит он востребован, что, в общем-то, не особо удивляет, т.к. ну привыкли мы уже так писать, и не особо хочется переучиваться.

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

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

У всех реализаций есть один существенный недостаток — их private и protected (если таковые имеются) поля и методы являются обычным фэйком, и, как правило, не составляет никаких проблем просто подменить arguments.callee._class на ClassWidthPrivateMethod — и вуа-ля, мы вызвали приватный метод извне. Язык, который позволяет что-то реализовать, с тем же успехом позволяет всё это обойти. Не менее неприятным моментом любой реализации является то, что заявления типа «при классическом подходе создаётся дикое количество экземпляров функций» полностью разбиваются о тот факт, что сама реализация создаёт внутри своих систем защиты не меньшее, а то и большее количество экземпляров одной и той же функции, при том, как правило, не самой маленькой. Так, спрашивается, зачем всё это нужно.

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

class.stanalone.js
run.init.js

Первый файл — это библиотека, предназначенная для standalone использования (в оригинальной реализации она является частью нашей платформы JACK), а второй — скрипт для тестирования.

Библиотека пока ещё достаточно сыра, да и её системы защиты, наверняка, можно обойти (кстати, если кто-то это сделает, то сообщите на akaj@evounit.ru, что бы я мог исправить ошибки). Но изучив её исходный код вы, возможно, что-то подчерпнёте для себя. Или, может быть, она просто вам пригодится в работе.

Интерфейс библиотека выглядит так:

Class() — функция для объявления нового класса.
Class.GUID() — функция возвращает уникальный идентификатор класса (может пригодится зачем).
Class.Self() — функция возвращает ссылку на сам класс.
Class.Superior() — функция возвращает ссылку на родительский класс.
Class.Interface(_index) — функция возвращает ссылку на интерфейс класса с индексом _index.
Class.Interfaces() — функция возвращает массив интерфейсов класса.
Class.ConstructorFunction() — функция вызывает конструктор применимо к своему контексту this.
Class.Create(...) — функция создаёт экземпляр класса и вызывает его конструктор с переданными параметрами.
Class.HeritableNames() — функция возвращает список членов класса.
Class.Extends(_superior) — функция указывает родительский класс.
Class.Implements(_interfaces|_interface1, _interface2, ...) — функция указывает интерфейсы класса. Аргументы можно передавать напрямую или в виде массива.
Class.OffspringOf(_ancestor) — функция проверяет, является ли класс потомком класса _ancestor.
Class.Constructor(_function) — функция указывает конструктор класса.
Class.Define(_list) — функция указывает члены прототипа класса. _list должен быть объектом, поля которого будут использованы для присвоения.
Class.Var(_access, _list) — функция указывает переменные класса. Доступ к переменной можно полчить в виде ClassInstance.varName() для считывания и ClassInstance.varName(varValue) для записи значения. _access должен быть строкой, которая может содержать следующие лексеммы: private (закрытые члены класса), protected (защищённые), public (открытые), static (статические члены или члены класса) и readonly (член доступен только для чтения).
Class.Method(_access, _list) — функция указывает методы класса. Объявлять метод readonly не имеет смысла.
Class.HasMethod(_function) — функция проверяет, есть ли у класса указанный метод.

Class.Create создаёт ClassInstance, которые обладает следующим интерфейсом:

ClassInstance.GUID() — функция возвращает уникальные идентификатор объекта.
ClassInstance.Self() — функция возвращает класс объекта.
ClassInstance.Superior() — функция возвращает ClassWrapper (см. ниже) для родительского класса.
ClassInstance.Interface(_index) — функция возвращает ClassWrapper для интерфейса с индексом _index.
ClassInstance.Interfaces() — функция возвращает массив ClassWrapper'ов для интерфейсов.
ClassInstance.Call(_name, ...) — функция осуществляет вызов метода по его имени.
ClassInstance.Wrap(_class) — функция создаёт ClassWrapper для класса _class.

ClassWrapper — этот оболочка для ClassInstance, представляющая её экземпляром указанного класса. Интерфейс оболочки выглядит следующим образом:
ClassWrapper.Self() — функция возвращает ссылку на класс оболчки.
ClassWrapper.Superior() — функция возвращает ClassWrapper для родительского класса класса оболочки.
ClassWrapper.Interface(_index) — функция возвращает ClassWrapper для интерфейса оболочки с индексом _index.
ClassWrapper.Interfaces() — функция возвращает массив ClassWrapper'ов для интерфейсов оболочки.
ClassWrapper.Construct(...) — функция вызывает конструктор класса оболочки применимо к ClassInstance.
ClassWrapper.Call(_method, ...) — функция вызывает метод прототипа класса оболочки применимо к ClassInstance.

Библиотека будет расширяться и дорабатываться. Я по прежнему рекомендую использовать возможность функционального программирования в JS, но библиотека — в помощь. По все вопросам вы можете писать на akaj@evounit.ru.

Спасибо за ваше внимание,
Александр Кай.

Говорит Лондон — европейские стартапы должны работать больше и лучше

Это перевод интервью, взятого у венчурного инвестора из Лондона. European startups need to work as hard as Valley ones – or forget it

Одна из проблем, стоящих перед инвесторами и основателями компаний — это нанять таланты. На ранних стадиях инвестирования состав команды может быть единственным критерием для принятия решения об инвестировании. То, что становится скоро понятным после занятий венчурным инвестированием, так это то, что абсолютное количество талантов в Европе/Великобритании меньше, чем в США. Рабочая этика (отношение к работе) также сильно различается.

Каждый, кто был в Силиконовой Долине, может заметить — там работают все время.

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

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

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

Не поймите меня неправильно (don’t get me wrong!), это не означает «быть в офисе». Офисные часы — только одно измерение. Я просто говорю о работе в целом — и просто быть онлайн, отвечать, присутствовать (twitter, IM, email, апдейты веб-сайта, релизы, обновления и т.д.).

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

Здесь культура «запустить и итерировать» (launch and iterate), а в Европе полагаются на устаревшую модель релизов. Это хорошо для ненапряжного лайфстайла, но плохо для создания быстро двигающихся вперед компаний. А быстрые компании требуют людей, которые их двигают в режиме 24х7.

По контрасту, что я наблюдаю в Европе: это мышление в стиле “это может подождать” или “не проблема, если мы позаботимся об этом завтра” или “да, сэр, это поставлено на очередь”. Вот в чем большая разница в восприятии мира!

И эта проблема не в том, в какие часы парни сидят на работе в офисе (или даже вне офиса). В Силиконовой Долине, даже если чуваки не работают или не на работе, они все равно работают. Даже когда они ходят в клуб, на вечеринки, за обедом или просто где-то зависают… Они работают, потому что каждый, с кем они зависают, находится в теме (in the industry), и поэтому это общение имеет прямое отношение к работе.

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

Но с точки зрения инвестирования, распространения знания вирусным путем, такая среда экстремально ценна. Это как одна большая чашка Петри. Сверх-мега-корпорация стартапов, где люди могут циркулировать между Google, Yahoo! Apple и другими компаниями. Это заставляет всех делать свою работу, думать о ней, буззить (buzzing) о ней все время.

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

Это, кстати, касается также отношения к выходным, праздникам и вообще свободному времени.

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

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

В Великобритании отпуск составляет 20 рабочих дней (3 недели!), и каждый следит — и, главное, использует эти 4 недели. В Долине это выглядело бы абсурдом, и если бы человек брал 4 недели каждый год, то он прослыл бы слэкером (прогульщиком, slacker). Подумайте о том факте, что даже количество дней отпуска по закону отличается в Европе и США в два раза!

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

Письмо с ФСБ РФ о нарушение закона проектом QIP

Доброго времени суток, вот решил запостить тут статейку, хочется узнать Ваше мнение по данному вопросу и правильности поступка.
Устал от внедрения всяких сервсов в КИП (Слово QIP, по правилам английского произношения читается как КИП) и слива информации и личных данных в сеть, а также получение огромного количества спама. Разработчики на контакт не идут, а на форуме только прихлебатели бегают по темам и пытаются заткнуть рот тем кто говорит что то плохое про КИП. Поэтому решил использовать ко ординальные меры для решения этого вопроса, поэтому написал письмо в ФСБ РФ

«Уважаемый Александр Васильевич.
Довожу до вашего сведения о нарушении закона N152-ФЗ «О персональных данных» от 27 июля 2006 г, который нарушается интернет проектом www.qip.ru, который разрабатывает QIP Infium — мультипротокольный клиент с поддержкой внешних модулей.
В результате установке данной программы по дефолту устанавливается (меняется) стартовая страница, поисковик и регистрируются сервисы без предупреждения об этом конечного пользователя. При этом в качестве логина и пароля были приведены реальные логин и пароль пользователя на qip.ru, а также реальные данные которые указываются при регистрации QIP Infium. Из чего можно сделать вывод, что:
1. Пароли к qip.ru хранятся в базе данных в открытом виде:
2. Доступ к базе данных с паролями имеют многие проекты, а не только команда разработчиков QIP
Без ведома пользователя стал вести микроблог, на сайте mblogi.qip.ru постятся статусы пользователей джаббера с сервера квипа без ведома конечного пользователя. Удалить себя из этого прекрасного сайта не представляется возможным. Позиционируется это как «сервис ориентированный на пользователей, предпочитающих умещать события своей жизни в короткие и емкие фразы», при этом происхождение сего ёмкого контента не раскрывается. Свои статусы можно посмотреть, подставив в конец ссылки mblogi.qip.ru/people свой логин. Тоже самое происходит и с другими сервисами внедренными в программу QIP Infium, а конкретней:
1. file.qip.ru — хранение файлов, идет автоматическая авторизация на сайте без ведома пользователя.
2. love.qip.ru — знакомства, идет автоматическая авторизация на сайте без ведома пользователя, создается анкета с реальными данными указанными при регистрации QIP Infium.
3. friends.qip.ru — социальная сеть, идет автоматическая авторизация на сайте без ведома пользователя, создается анкета с реальными данными указанными при регистрации QIP Infium, личный список контактов добавляется в друзья и выводится в свободное распространение.
4. memori.qip.ru — закладки, идет автоматическая авторизация на сайте без ведома пользователя, создается анкета с реальными данными указанными при регистрации QIP Infium.
5. Хранение Логинов, паролей, настроек и истории переписке на серверах QIP Infium – происходит по дефолту
6. И многое другое.
Также разработчики использует базу логинов и паролей для создания аккаунтов на левых сайтах от имени, но без ведома пользователя — у каждого пользователя QIP Infium ВНЕЗАПНО появились аккаунты на всяких сайтах как с порнографическим содержанием так и с рекламным характером, на указынные при регистрациях данные (электронная почта) идет большое количество спама с порнографическим и рекламным характером.
При возникновении подобных тем на форуме qip.ru разработчики не как не комментируют это, подобные темы быстро закрываются.
Нечего подобного в пользовательском соглашении при установки программы не пишется. Более того, при выборе русского языка установки, предлагается безальтернативно ознакомиться с английским соглашением.
В результате всего мышее перечисленного программа QIP Infium нарушает:
1. закон N152-ФЗ «О персональных данных»
2. КоАП РФ. Статья 13.11. Нарушение установленного законом «О персональных данных» порядка сбора, хранения, использования или распространения информации о гражданах (персональных данных)
3. КоАП РФ. Статья 13.14. Разглашение информации с ограниченным доступом
4. КоАП РФ. Статья 5.39. Отказ в предоставлении гражданину информации
5. УК РФ. Статья 137. Нарушение неприкосновенности частной жизни
6. УК РФ. Статья 140. Отказ в предоставлении гражданину информации
7. УК РФ. Статья 272. Неправомерный доступ к компьютерной информации
Прошу вас принять меры но устранению данных нарушений и наказу виновных в их не соблюдении.

С уважением к Вам…
Телефон +7…

Паспорт ..........................................»

Вот и скрины
Изображение с кодом 82382 - savepic.org — сервис хранения изображений
Изображение с кодом 94670 - savepic.org — сервис хранения изображений

ЗЫ Подобное письмо отправил еще в МВД РФ и Ген Прокуратуру РФ

Теперь хочу знать ваше мнение.

простой, но звездный рейтинг на JQuery

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

Подчеркну, что интересовала именно UI часть, ибо запись в БД и обработка рейтинга уже сделана на JAVA.
Сейчас на множестве блогов и новостных сайтов используется «звездный» подход для определения рейтинга комментария, статьи, новости. Удобно и приятно.
Обычно это 5 звездочек. При клике на одну из них выставляется соответственная оценка.
В сети нашел множество примеров для этого дела — на JQuery, с использованием AJAX и «обычного» JS.

Порывшись и на хабре, нашел ссылки на некоторые примеры:
http://www.fyneworks.com/jquery/star-rating/#tab-Testing
http://www.m3nt0r.de/devel/raterDemo/

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

И вот что из этого вышло:

1) маленький star rating с использованием JQuery, скриптовая часть занимает 57 строк;
2) CSS для затемнения звездочек при наведении мыши с помощью стандартных CSS фильтров;
3) соотвественно HTML часть для отображения всего этого безобразия.

Прошу пинать и жаловать!

JS часть

$(document).ready(function() {

var starId = "[id*='star']";
var curRatingId = "[id*='curRating']";
var starredId = "[id*='starred']";

//mouse over handling
$(starId).bind(('mouseenter'), function(){
starIndex = $(this).attr('id').substr(4);
$('#curRating' + starIndex).show();
$('#rating').hide();

});

$(starId).bind(('mouseleave'), function(){
starIndex = $(this).attr('id').substr(4);
$('#curRating' + starIndex).hide();
$('#rating').show();
});

$(starredId).bind(('mouseenter'), function(){
starIndex = $(this).attr('id').substr(7);
$('#curRating' + starIndex).show();
$('#rating').hide();
});

$(starredId).bind(('mouseleave'), function(){
starIndex = $(this).attr('id').substr(7);
$('#curRating' + starIndex).hide();
$('#rating').show();
});

//opacity handling
$(starId).click(function() {
starIndex = $(this).attr('id').substr(4);
for (var i=1;i<=starIndex;i++){
$('#star' + i).hide();
$('#starred' + i).show();
$('#starred' + i).parent().removeAttr('class');
}
$('#rating').html(starIndex);
});

$(starredId).click(function() {
starredIndex = $(this).attr('id').substr(7);
for (var i=1;i<=starredIndex;i++){
$('#starred' + i).show();
$('#star' + i).hide();
}

for (var y=parseInt(starredIndex)+1;y<=5;y++){
$('#starred' + y).hide();
$('#star' + y).show();
}
$('#rating').html(starredIndex);
});
})


один архив с HTML и CSS

http://www.easy-share.com/1908532338/star.rar

совместимость

Протестировано и работает в следующих браузерах:
FF 3.5.5; IE (7); IE8; IE6; Opera 10.00; Chrome 3.0.195.33; Safari 4 (Public Beta).
В IE 5.5 к сожалению, не работает ))

Жду ваших комментариев советов по минимизации.

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