воскресенье, 21 декабря 2008 г.

Qt Creator

Qt Software (так называется Trolltech после покупки компанией Nokia) выпустили бету новой кросс-платформенной IDE для работы с Qt - Qt Creator. На данном этапе среда поддерживает только компилятор gcc и дебагер gdb. Можно так же использовать Microsoft Visual Studio компилятор, но тогда не получится дебажить.

Qt Creator - это не попытка заменить Eclipse и Visual Studio:

Qt Creator is not an Eclipse replacement, but instead a lightweight IDE designed specifically for cross-platform Qt development.

Qt Creator is not a Visual Studio replacement, but instead a lightweight IDE designed specifically for cross-platform Qt development.

Финальный релиз намечается на начало 2009 года. Подробнее можно почитать здесь.

Выглядит это так:



Самореклама: мой второй блог

Read More...

суббота, 20 декабря 2008 г.

1+1=4

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

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

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

Самореклама: мой второй блог

Read More...

пятница, 19 декабря 2008 г.

Бесконечные проекты

Навеяло постом про собеседования.

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

Read More...

вторник, 2 декабря 2008 г.

Рассуждения вместо уравнения

В "Математической смекалке" довольно красиво показано как решение задачи плавно вытекает из условия при помощи простых рассуждений и элементарных вычислений:

Если некоторое двузначное число прочесть справа налево, то полученное "обращенное" число будет в 4.5 раза больше данного. Что это за число?

В условии задачи данных немного, но, искусно их используя, можно решить эту задачу одними "рассуждениями" примерно так:
1. Искомое число больше 10, так как оно двузначное.
2. Но оно меньше 23, так как 23*4.5 - число трехзначное.
3. Искомое число четное, так как при умножении его на 4.5 получается целое число.
4. Обращенное число по условию в 9 раз больше половины данного числа, значит, обращенное число кратно 9.
5. Так как обращенное число кратно 9, то сумма его цифр делится на 9, а данное число состоит из тех же цифр, что и обращенное, значит, и оно кратно 9.
...
Дальше уже не сложно продолжить рассуждения и найти искомое число.

Read More...

понедельник, 1 декабря 2008 г.

Утренний артхаус

Сегодня в 5 утра ехал на такси на вокзал. Всю дорогу таксист рассказывал как он прикручивал индексацию на ассемблере для базы данных, хранящейся на 8-ми дюймовой дискете...

Read More...

пятница, 28 ноября 2008 г.

Кризисный оффтоп: "увольнения"

То, что экономический кризис не коснулся меня лично, не значит, что его нет. Среди моих знакомых, работающих в банках и тому подобных организациях, уже есть пострадавшие, которых "уволили". Я не зря взял это слово в кавычки - странно называть увольнением, когда человека вынуждают писать заявление по собственному желанию. Я сужу со своей колокольни и поэтому не понимаю, что значит вынуждают? Что мешает человеку, отработавшему на одном месте больше года, отказаться писать заявление по собственному желанию? Страх, что в трудовую напишут какую нибудь гадость? Но насколько я знаю, написать гадость не так то просто, КЗОТ хоть как-то от этого должен защищать. Возможно дело именно в незнании своих прав и вынуждение - это эксплуатация работодателями этого незнания?

Получаются одни вопросы. Может ли кто-нибудь объяснить мне такое положение дел?

Read More...

четверг, 27 ноября 2008 г.

Тестирование "белого ящика"

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

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

// типы треугольников
enum type_t {t_scalene=1, t_isosceles=2,
t_equilateral=3, t_error=4};

type_t triangle_type(int sideA, int sideB, int sideC)
{
// проверка валидности треугольника -
// сумма длин двух любых сторон не должна превышать
// длину третьей стороны
if((sideA>0 && sideB>0 && sideC>0) && // 1
(sideA<(sideB+sideC))&&
(sideB<(sideA+sideC))&&
(sideC<(sideA+sideB)))
{
int ab = (sideA==sideB)?1:0; // 2
int ac = (sideA==sideC)?1:0; // 3
int bc = (sideB==sideC)?1:0; // 4

int num = ab+ac+bc;

// if num==0 - scalene
// if num==1 - isosceles
// if num==3 - equilateral
type_t types [] = {t_scalene, t_isosceles,
t_error, t_equilateral};
return types[num]; // 5
}

return t_error;
}

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

Почему одного запуска функции и получение нужного результата недостаточно? Программы очень редко выполняются строчка за строчкой - этому препятствуют всевозможные логические операторы if, for, while, until, or, and, switch. Они разветвляют код, создавая сложные пути исполнения одной и той же программы при разных входящих данных. И по всем этим путям нужно пройти, один запуск с одними параметрами - это проверка одного пути из многих. Значит тестов нужно не меньше, чем перечисленных выше ключевых слов в коде. (В рассматриваемом случае под тестами я понимаю вызов функции с различными наборами параметров.)

Первый if, в приведенной выше функции, проверяет четыре условия - длины сторон треугольника должны быть неотрицательными и длина каждой из сторон должна быть меньше суммы длин двух других. Все условия объединены операторами &&, поэтому достаточно невыполнения одного из них, что бы не выполнился код, следующий за if. Но неплохо бы знать, все ли условия вычисляются правильно. Поэтому нужно передать функции значения, которые будут true и значения, которые будут false для каждого из условий. Проверить это можно по возвращаемому значению t_error, в случае если любое из условий не выполняется. Хотя первое из условий является само по себе составным, но все проверки в нем довольно простые и объеденены оператором &&, поэтому допустим, что достаточно будет проверки, когда одна длина отрицательная и когда все длины положительные.

В случае успешного прохождения if, выполняются проверки, помеченные как 2, 3, 4. Они не создают больших ответвлений, но вычисляют значения, которые влияют на выбор нужного элемента массива types в строке 5. Количество выполненных условий записывается в переменную num, которая может принимать только три значения 0, 1, 3 (2 не может быть, так как при выполнении двух автоматически выполняется третье). Значит для тестирования этой части кода достаточно 3-х наборов входящих параметров - все стороны неравны (num==0), все стороны равны (num==3), равны только 2 стороны (num==1).

Больше ответвлений в программе не наблюдается, поэтому можно подводить итог. Для тестирования функции triangle_type, нужно передать ей 14 наборов входящих параметров (8 для условия 1, 6 для условий 2, 3, 4) и проверить возвращаемый результат. После этого можно быть уверенным, что в большинстве случаев поведение функции будет предсказуемым. Хотя нет... это только часть возможных проверок. Еще можно проверять передаваемые параметры, например, как будет вести себя функция при максимально и минимально допустимых значениях, но это уже отдельная тема. Я хотел рассказать только о тестировании, базирующемся на изучении кода. Это как раз то, что теоретически отличает тестирование программистами от тестирования тестировщиками - программисты тестируют не "черный ящик".

PS: Не смотря, на то что получилось много текста, на практике это занимает не так уж много времени :)

Read More...

суббота, 22 ноября 2008 г.

Задача про банку и дробь

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

Read More...

среда, 19 ноября 2008 г.

Удивительное рядом - shared_ptr и виртуальный деструктор

Интересную штуку про boost::shared_ptr прочитал здесь Storing dynamicly created objects in a container. Для shared_ptr не обязательно наличие виртуального деструктора у базового класса. Это не значит, что виртуальные деструкторы теперь не нужны, но может быть полезно, когда есть legacy-код без них и менять его нельзя.

Read More...

воскресенье, 16 ноября 2008 г.

Объединение двух отсортированных массивов

Как объединить два отсортированных массива (n1 и n2 элементов) в один отсортированный массив? Такой вопрос мне неоднократно попадался на собеседованиях и даже пару раз сталкивался с ним на практике. Вся сложность этого вопроса не в том как это сделать, а как это сделать максимально быстро.

Быстрее всего это делается за n1+n2 итераций (линейное время). Пусть есть два отсортированных по возрастанию массива A1 и A2. Можно легко определить первый элемент результирующего массива - им будет либо первый элемент первого массива, либо первый элемент второго массива, в зависимости от того, что меньше. Допустим, наименьший - это A1[0]. На следующей итерации при помощи одного сравнения определяется второй элемент результирующего массива - опять сравниваются первые элементы исходных массивов, при условии, что для A1 первый элемент - это A1[1], так как A1[0] - уже выбыл из игры. И так продолжается пока не будет заполнен результирующий массив. На картинке это выглядит так:


Как видно, ничего сложного в этом алгоритме нет. Самое интересное в нем - это возможность использования для сортировки. Любой массив размера n можно представить в виде n массивов, состоящих из одного элемента. Пары соседних элементов, представленных ввиде массивов можно объединять по описанному выше алгоритму. Получится примерно в 2 раза (примерно, потому что n может быть как четным так и нечетным числом) меньше отсортированных массива по 2 элемента, которые в свою очередь тоже можно объединить. И так пока не получится один отсортированный массив.
А все это называется сортировка слиянием.

Read More...

суббота, 15 ноября 2008 г.

Concepts в C++0x

Наконец то удалось посмотреть видео о новых расширениях С++ Concepts: Extending C++ Templates For Generic Programming. Решил поделиться своими впечатлениями.

Concepts - это расширение существующих шаблонов С++, позволяющие устанавливать требования к параметрам шаблона. Концепция позволяет ответить на несколько вопросов:

  • чем должен быть параметр?
  • что он должен уметь делать?
  • как установить соответствие между параметром и тем, чем он должен являться?

В ролике это называлось Concept definitions, Where clauses и Concept maps соответственно. Насколько я понимаю, то, что было озвучено и то, что будет в стандарте немного отличается, по крайне мере вместо where будет использоваться requires, поэтому пример будет выглядеть не как в видео:
// Вычисление суммы элементов последовательности

// Параметр шаблона должен быть Forward Iterator -
// позволяет двигаться только в перед
template< ForwardIterator Iter >
// два значения, на которые указывают итераторы,
// могут быть сложены при помощи оператора +
requires Addable< Iter::value_type >,
// объект, на который указывает итератор,
// должен иметь оператор присваивания
&& Assignable< Iter::value_type >
Iter::value_type sum(Iter first, Iter last,
Iter::value_type result)
{
for (; first != last; ++first)
result = result + *first;
return result;
}

// у типа double* нет оператора сложения, присваивания,
// получения следующего элемента последовательности,
// но реализация алгоритма sum будет корректно работать
// с этим типом, поэтому устанавливается соответствие
// между ForwardIterator и double*
concept_map ForwardIterator {
typedef double value_type;
};

Надеюсь, теперь понятно, зачем вводятся concepts, если нет, то подробней можно почитать здесь: ConceptC++ Tutorial.

На видео, дядька приводит другой пример, знакомый всем, кто использовал STL: простой алгоритм поиска, реализованный в соответствие с требованиями STL, отлично работает с вектором, но не хочет работать со списком. Хотя внешне все вписывается в общую структуру библиотеки: контейнеры - итераторы - алгоритмы. Для того, что бы понять, что не так с алгоритмом нужно копаться в его коде либо использовать concepts. Начиная с этого места у меня появилось чувство, что concepts - это костыль, который подсовывают С++. Проблема как была, так и осталась, но теперь можно уверенно хромать в перед. Лечится только следствие проблемы - теперь компилятор будет сам говорить, что хотя все вписывается в рамки, но работать все равно не будет. При этом, возможность писать неработающий код так и остается - для совместимости с предыдущими версиями.

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

Это первое впечатление, основанное на двухчасовом знакомстве с этим нововведением. Надо будет еще обдумать прочитанное и просмотренное, а то прям бесполезная какая-то штука получается :) Поэтому интересно было бы услышать критику моего обзора и мысли по поводу concepts.

Read More...

четверг, 13 ноября 2008 г.

Задачка про прилив

Нашел в шкафу старую книгу "Математическая смекалка". Замечательная книга! Теперь по вечерам сижу с удовольствием решаю задачки - неплохая гимнастика для мозгов и хорошая альтернатива вечернему созерцанию интернета. Вот одна из задач, которая мне понравилась (кстати, ничем не хуже майкрософтовских :)

Недалеко от берега стоит корабль со спущенной на воду веревочной лестницей вдоль борта. У лестницы 10 ступенек; расстояние между ступеньками 30 см. Самая нижняя ступенька касается поверхности воды. Океан сегодня очень покоен, но начинается прилив, который поднимает воду за каждый час на 15 см. Через сколько времени покроется водой третья ступенька веревочной лесенки?

Read More...

вторник, 11 ноября 2008 г.

Python 3 Patterns & Idioms

Стала доступна open source книга Python 3 Patterns & Idioms, написанная Bruce Eckel при содействии Python community. Она распространяется под лицензией Creative Commons Attribution-Share Alike 3.0 (первый раз о такой слышу :).

Книга еще сыровата, по крайне мере в содержании все перемешано в кучу и некоторые главы отсутствуют. Большая часть посвящена паттернам, например, есть много про singleton, есть много про Jython, немного про юнит тестирование и TDD, рефакторинг, а так же упражнения к каждой главе. Самое интересное, что здесь кода больше, чем букафф :)

Read More...

среда, 29 октября 2008 г.

Задача о шляпах от Microsoft

На лестнице стоят 4 человека. Самый верхний стоит на ступеньке, спрятанной за непроницаемой стеной и не видит никого. Все остальные видят только вышестоящих: A видит B и С, B видит C, С видит стену.

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

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

ЗЫ: Выглядит это примерно так:

Read More...

понедельник, 27 октября 2008 г.

Поиск последовательности в массиве

Задача

Есть массив положительных и отрицательных чисел. Нужно найти последовательность значений, сумма которой будет наибольшая. Например, для массива [-2, 5, -5, 8, -1, 3, 2, 6] наибольшая сумма будет для последовательности [8, -1, 3, 2, 6].

Решение

Пусть нам дан массив:

src_aray = [x1, x2, x3, x4]

Тогда для решения поставленной задачи нужно вычислить и найти наибольшее для следующих последовательностей:

x1+x2+x3
x2+x3
x1
x2+x3+x4
x2+x3
x2
x3+x4
x3
x4


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

Тогда алгоритм будет такой:
1. Массив проверяется на наличие положительных чисел.
2. Пошагово проверяем каждый элемент массива xi.
3. Если в массиве нет положительных чисел (худший вариант), вычисляем сумму всех последовательностей, начинающихся с xi.
4. Если в массиве есть положительные числа, вычисляем сумму всех последовательностей, начинающихся с xi, только в случае xi > 0.
5. Среди вычисленных сумм, выбираем наибольшую.

Реализовать этот алгоритм можно так:


// допускаем, что данные всегда передаются валидные
// src_array - исходный массив
// len - его длина
// sindex, eindex - результат поиска - начальный и
// конечный индексы последовательности
void sub_array(int *src_array, int len,
int &sindex, int &eindex)
{
int sum = src_array[0];
sindex = 0;
eindex = 0;

// проверяем наличие положительных значений
bool has_positive = false;
for(int i=0;i < len;i++)
if(src_array[i]>0)
{
has_positive = true;
break;
}

for(int i=0;i < len;i++)
{
int ssum = src_array[i];
if(has_positive && ssum < 0) continue;

for(int j=i;j < len;j++)
{
ssum += j>i?src_array[j]:0;
if(ssum>=sum)
{
sum = ssum;
sindex = i;
eindex = j;
}
}
}
}

Read More...

воскресенье, 26 октября 2008 г.

Поиск дубликатов в массиве

Задача

Есть массив целых от 1 до N. Нужно определить, есть ли в этом массиве повторяющиеся значения.

Решение

Задачу можно решить несколькими способами. Первое, что приходит в голову - отсортировать исходный массив и сравнивать соседние элементы. Затраты по времени и по расходуемой памяти будут зависеть от алгоритма сортировки, например, при быстрой сортировке временная сложность будет O(nlogn +n-1) и емкостная сложность (память) будет O(logn).


Другое решение - пошагово обходить массив и в каждой итерации проверять значение элемента, сравнивая с информацией о предыдущих итерациях, сохраняемой в дополнительном контейнере. Таким контейнером может быть массив размера N и полностью заполненный нулями. Индекс элемента в массиве - значение от 1 до N (точнее от 0 до N-1), значение элемента - количество "индекса" в исходном массиве. Это проще выглядит на примере:

// исходный массив, со значениями от 1 до 9
src_array = [1,3,8,4,2,9,3,9]

// дополнительный массив на 9 элементов (что бы уместились от 1 до 9)
add_array = [0,0,0,0,0,0,0,0,0]

// после обработки исходного массива результирующий будет выглядеть так:
// одна единица, одна двойка, две тройки, одна четверка, одна восьмерка и две девятки
add_array = [1,1,2,1,0,0,0,1,2]


Сложность такого алгоритма будет O(n), затраты памяти будут зависеть от диапазона данных - O(maxN-minN). Кроме этого, требуется, что бы было известно максимальное значение элементов из исходного массива, в противном случае либо будет затрачиваться дополнительное время на его поиск, либо понадобиться значительно больше памяти (например, что бы поместить все целые числа).

Вывод

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

Read More...

суббота, 25 октября 2008 г.

Абстрактный класс VS интерфейс

Недавно меня озадачили вопросом: чем отличается абстрактный класс от интерфейса в С++? Я вроде бы не настолько забыл С++, что бы помнить об абстрактных классах, но не помнить об интерфейсах.

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

Ни о каких интерфейсах в стандарте С++ не говориться, кроме того, что абстрактный класс может предоставлять интерфейс, который реализуется наследниками (10.4.1):

An abstract class can also be used to define an interface for which derived classes provide a variety of implementations.

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

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

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

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

Read More...

четверг, 16 октября 2008 г.

Windows исключения

Интересное описание устройства исключений в Windows (не тех, которые C++-исключения): А что, собственно, происходит, когда бросается исключение?

Read More...

PyQt in-depth: типы signal-slot соединений

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

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


  • DirectConnection - прямое соединение, когда сигнал моментально обрабатывается слотом;

  • QueuedConnection - сигнал добавляется в очередь и ожидает своего "выхода" в очереди сообщений, при этом поток, в котором возник сигнал не блокируется;

  • BlockingQueuedConnection - то же, что и QueuedConnection, но вызывающий поток блокируется, пока сигнал не будет обработан;

  • AutoConnection - автоматически выбирается DirectConnection, если сигнал вызывается из того же потока, в котором живет приемник, и QueuedConnection, если используются разные потоки.

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

Тип соединения указывается как параметр QObject.connect:

QObject.connect(doer, SIGNAL('event'), self.handle, Qt.DirectConnection)

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

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

В случае DirectConnection, сигнал обрабатывается синхронно, в потоке, где выполнялась задача:

task in thread < Thread(Thread-1, started) >
handle in thread < Thread(Thread-1, started) >
handle finish
after notify


При QueuedConnection, сигнал обрабатывается асинхронно в главном потоке приложения:

task in thread < Thread(Thread-1, started) >
after notify
handle in thread < _MainThread(MainThread, started) >
handle finish


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

task in thread < Thread(Thread-1, started) >
handle in thread < _MainThread(MainThread, started) >
handle finish
after notify


При AutoConnection ситуация такая же как и при QueuedConnection, так как сигнал и приемник в разных потоках:

task in thread < Thread(Thread-1, started) >
after notify
handle in thread <_MainThread(MainThread, started)>
handle finish


Но если изменить одну строчку кода результат будет таким же как при DirectConnection:

task in thread <_MainThread(MainThread, started)>
handle in thread <_MainThread(MainThread, started)>
handle finish
after notify


Тип соединения BlockingQueuedConnection стоит использовать только в многопоточных приложениях, так как в одном потоке может привести к dead lock'у, о чем Qt должно предупредить ворнингом:

Qt: Dead lock detected while activating a BlockingQueuedConnection

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

Read More...

среда, 15 октября 2008 г.

Неосторожность с lambda

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

Но результат выполнения этого кода получился неожиданный:

item a result c
item c result c
item b result c


Проблема оказалась в строке:
m.addAction(item, lambda : item)

lambda использует переменную item из контекста вызывающей функции. Переменная изменяется в цикле и к моменту вызова lambda в item сохраняется значение последней итерации.

Отсюда вывод - смешивание функционального подхода и "обычного" может привести к самым неожиданным результатам. Для того, что бы избежать такого смешивания, достаточно заменить цикл на map:
map(lambda item: m.addAction(item, lambda : item), lst)

Read More...

воскресенье, 28 сентября 2008 г.

Отзыв об Exception #09

Скажу сразу, что 9-тый Exception понравился мне намного больше, чем 7-й (на 8-м я не был). Причин тому несколько: темы были не "узконаправленные", что показало, что python - не только для веба; выступлений было не много - один мастер класс и два небольших доклада; Open Space показал себя как отличный способ для неформального обмена опытом.

Первым выступал Сергей Щетинин с мастер-классом "Trellis. Приложения основанные на обработке сообщений". Только ради того, что бы узнать о Trellis, стоило пойти на этот семинар. Для меня, фанатеющего от event-driven architecture - это было то, чего мне так давно не хватало: полностью автоматизированный обмен и обработка событий (без использования колбеков) и изолированность вычислений от сторонних эффектов. Это идеально подходит для создания GUI, когда многие виджеты зависят от многих данных.

Trellis позволяет создавать компоненты, у которых автоматически отслеживаются изменения атрибутов (созданных при помощи attr()), при использовании этих атрибутов в зависимостях (зависимости - декорированные функции, использующие эти атрибуты):

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

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

Последний небольшой доклад делал Максим Ищенко об автоматизации управления несколькими серверами при помощи питоновской тулзы Fabric.

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

Read More...

среда, 13 августа 2008 г.

Синглтон в 3 строки

Сегодня показали интересную реализацию синглтона на питоне:

Read More...

понедельник, 11 августа 2008 г.

default параметр в getattr

В примере увидел интересный способ использования getattr. Третий необязательный параметр функции (getattr( object, name[, default])) - значение, которое будет возвращено, если атрибута с указанным именем не существует. Если использовать лямбду, которая делает "ничего" - lambda : None, то во многих случаях можно отказаться от использования дополнительной функции hasattr:

Read More...

пятница, 8 августа 2008 г.

Оператор with в Python

В прошлом посте я жаловался, что в Python мне не хватает чего-то похожего на C++-ные деструкторы, которые вызываются в любом случае для объекта созданного в стеке при выходе из области видимости, даже когда возникает исключение. В комментария, AQUAGNU упомянул оператор with, который в Python 2.5 был еще на "птичьих правах" (для его использования надо импортировать with_statement из модуля __future__), а в 2.6 стал зарезервированным словом.

Оператор with автоматизирует выполнение операций при входе в блок кода и при выходе из него не зависимо от того, было ли исключении при исполнении блока. Под операциями входа в блок и выхода из блока имеется ввиду, например, открытие и закрытие файла, залочивание и разлочивание при синхронизации. Это можно делать (как я раньше и делал) при помощи try/finally:
with все несколько упрощает:
Объект, который подается на вход with, называется менеджером контекста. У него должен быть реализован протокол менеджера контекста, состоящий из двух методов:
__enter__() - вызывается перед началом выполнения блока (контекста);
__exit__(type, value, traceback) - вызывается по завершению выполнения блока. Параметры, передаваемые ему, описывают исключение, если блок его сгенерировал.

В общем виде это выглядит так (взято отсюда):

В 2.5 версии контекст менеджерами могут выступать файлы, thread.LockType, threading.Lock, threading.RLock, threading.Condition, threading.Semaphore, threading.BoundedSemaphore. Применение with для Lock было показанное во втором примере. Для остальных случаев, прийдется реализовать протокол менеджера контекста или сделать адаптер:

Вот такой вот забавный оператор with.

PS: оказывается with был еще в делфи
PS2: дополнительно можно почитать здесь и здесь.

Read More...

вторник, 29 июля 2008 г.

Стартап: что мы делаем?

Прошло около 3-х месяцев как стартовал наш проект. Сегодня на хабре появилась первая информация о том, что мы делаем: Интеграция пользователей в социальный граф. Подход MetaID

Read More...

пятница, 11 июля 2008 г.

Любимая С++ фича

В своем посте My Favorite C++ Feature автор говорит, что его любимая фича в С++ - деструкторы. Согласен с ним в это на 100%, особенно вызов деструктора при выходе из области видимости. Использовать подобные конструкции мне доставляет прямо таки эстетическое удовольствие:

Это позволяет писать более читабельный код, не используя лишний раз try-catch. И это как раз то, чего мне сейчас не хватает в Python'e. Хотя, там есть деструкторы (__del__), но не факт, что он вызовется в нужный мне момент.

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

Вообще, тему С++ фич можно расширить - фичи с использованием С++. Здесь я могу назвать два своих самых любимых паттерна - smart pointer (как раз из-за деструкторов) и visitor (за возможность добавления новой функциональности иерархии классов без внесения изменения в их код и за возможность избежать использование dynamic_cast). А какие ваши самы любимые С++ фичи?

Read More...

четверг, 3 июля 2008 г.

Завязывайте вы с этим С++

Только что прочитал крик души бывшего С++ программиста - Язык имеет значение. Как-то все слишком складно получается - перешел на Haskell - получил 40% сэкономленного времени. А че ж никто не переходит? Никто что ли не слышал про него?

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

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

Read More...

среда, 18 июня 2008 г.

Поаутсорсить на Индию???

Сегодня мне звонил чувак (HR какой-то компании) аж из Индии и на довольно сносном русском предлагал поработать на них... Неужели я что-то пропустил и индусы уже нанимают украинцев?

Read More...

пятница, 30 мая 2008 г.

В восторге от Python'a

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

Например, мне нужно было сделать следующее: C++-ный код запускает Python-скрипт, который обрабатывает некоторые данные. Пользователь может захотеть написать свои обработчики для конкретных данных. Сложность состояла в том, как объяснить исходному скрипту, что есть другие реализации. Вот как позволяет это делать Python:


Теперь, все что надо пользователю - это написать класс с именем тип_данныхExt и методом process_data() и сохранить его в файле тип_данных.py. Получается намного проще, чем делать это на С++, причем проще и для разработчика и для пользователя.

Read More...

понедельник, 12 мая 2008 г.

До свиданья, аутсорсинг

Сегодня наконец-то решил сменить стабильную работу в аутсорсинговой компании на стартапный проект. За более чем год работы в аутсорсинге пришол к выводу, что такая работа стабильная не только в материальном плане, но и в плане скучности (тут я имею ввиду С++-проекты).

"Скука, скука, рутина, рутина..." (с) Кирпичи

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

Read More...

среда, 30 апреля 2008 г.

Ну Фаулер, насмешил

Пример из статьи Фаулера CollectionClosureMethod:


... The partition method combines select and reject. It works well with the multiple assignment feature in ruby.

managers, plebs = employees.partition{|e| e.manager?}

Теперь буду расшифровывать ПМ как "патриций-менеджер".

Read More...

вторник, 8 апреля 2008 г.

Враги...

Акция "Врагов надо знать в лицо": найди свой пост на сайте врага без ссылки на источник.

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

Read More...

среда, 2 апреля 2008 г.

Расширения Firefox #1

Недавно решил немного разобраться как расширяется Firefox (навеяло конкурсом от Mozilla). По ходу сделал небольшой конспект - может когда нибудь пригодиться или будет кому-то интересно.

Часть первая. Firefox из нутри.

Firefox предоставляет несколько основных путей для своего расширения, каждый из которых отличается не только по назначению, но и способом создания: плагины (plugins), расширения (extensions), тулзы для поиска (search engines, search plugins). Все вместе это называется add-ons. Плагины - это бинарные компоненты, которые помогают браузеру отображать специфические данные, например, pdf-файлы. В отличие от них, расширения добавляют новую функциональность и позволяют изменять пользовательский интерфейс (например, какой-нибудь хитрый поиск по открытому документу при нажатии большой красной кнопки на статус-баре). Отдельно стоят search plugins -плагины, которые специализируются только на поиске.

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

Исходя из Conceptual Architecture of Firefox и Firefox Concrete Architecture, браузер состоит из нескольких составных: GUI, Browser Engine (функциональность браузера - инициирование загрузки ULR, refresh, forward, back..), Rendering Engine (отрисовка контента и GUI браузера), Data Persistent (настройки пользователя), Networking (поддержка различных протоколов, кэширование, кодировки, безопасность), JavaScript interpreter, XML parser, Display Backend. Browser Engine и Rendering Engine в Firefox представлены одним модулем - Gecko.

Все, что мы видим, запуская Firefox - результат работы Gecko. Он рендерит не только контент браузера но и GUI. Для поддержки различных диалектов XML и HTML, Gecko использует XML-парсер (Expat). Одним из таких диалектов является XUL (читается "зул") - кроссплатформенный XML-based язык для описания пользовательского интерфейса. С XUL тесно связан XPToolkit - набор XUL-виджетов, таких как тулбары, меню, кнопки и т.д. Если XUL - это совокупность правил, атрибутов, элементов и связей между ними, то XPToolkit - это строительный материал для GUI, выраженный в понятиях XUL. Парсер представляет XUL в виде надмножества DOM - Application Object Model (AOM) - иерархия виджетов (браузер, меню, элемент меню и т.д.). Таким образом, для Gecko не имеет значения, что он получает на входе - XML, XUL или HTML.

Для работы с JavaScript, Gecko использует JavaScript интерпретатор - SpiderMonkey.


Теперь становиться понятно, какое место занимают плагины, а какое - расширения. Плагины занимаются рендерингом, значит должны взаимодействовать непосредственно с Gecko, использовать его API (Gecko Plugin API). Расширения меняют пользовательский интерфейс и добавляют новые фичи, значит должны подсовывать Gecko соответствующие XUL-файлы и JavaScript'ы, соовокупность которых и будет расширением.

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

  • package_name - имя пакаджа; может быть как именем расширения, так и касаться базовой функциональности (например, chrome://browser/content/browser.xul - xul-файл, описывающий GUI браузера);
  • data_type - тип запрашиваемых данных (какие они бывают будет описано дальше);
  • file_path - путь к конкретному файлы в chrome.

Загруженные таким образом файлы получают неограниченные права (chrome-privileges). Вообще, chrome, в терминологии Mozilla - это все, что не веб-контент, а именно, GUI и все, с ним связанное (xul, js, css и т.д.). Основные типы chrome:
  • content - это, можно сказать, строительный материал для приложения на базе Firefox(xul, js).
  • locale - информация, позволяющая автоматизировать использование различных языков в зависимости от текущей локали.
  • skin - css-файлы, описывают как будут отображаться виджеты.

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

Ссылки:
Conceptual Architecture of Firefox
Firefox Concrete Architecture
XUL Tools and What They Mean
Mozilla developer center

Read More...

понедельник, 24 марта 2008 г.

gdbлин

Вот такие штуки позволяет делать gdb.

Read More...

среда, 19 марта 2008 г.

blog update

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

Read More...

понедельник, 17 марта 2008 г.

Exception Conference #07, впечатления

В минувшую субботу в Киеве прошла очередная всеукраинская конференция по динамическим языка программирования Exception. Изначально, Exception собирала приверженцев Python'a. Но на седьмой по счету конференции, на ряду с Python'ом, были доклады, касающиеся Ruby, Smalltalk, Groovy и REBOL.

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

Первыми выступали Алексей Баран "Smalltalk - опыт применения" и Андрей Светлов "Мастер-класс по Python: Метаклассы + Дескрипторы" (малый зал).

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

Переместившись со своим стулом в соседний зал, я успел послушать часть доклада по метаклассах и дескрипторах в Python'e. Доклад был даже не совсем докладом, Андрей просто сел за комп, запустил редактор и начал писать код, объясняя что и к чему. Здесь все происходило более живо, был фидбэк от слушателей, постоянно звучали вопросы. Но, так как в Питоне я не в зуб ногой, то полезной информации я получил не так уж много.

К сожалению, не было доклада Вадима Войтюка "Groovy - другой взгляд на Java", поэтому следующим шел объединенный на два зала доклад Сергея Щетинина "По ту сторону ООП: PEAK-Rules и PyProtocols". Сергей выступал на Exception'e не первый раз, поэтому, учитывая минусы прошлых выступлений, старался сделать свой доклад максимально интересным не только питонистам. Как не питонист, могу сказать, что ему это в принципе удалось. PEAK-Rules и PyProtocols - это библиотеки расширяющие возможности generic functions, мультиметодов и, самое основное, позволяющие эффективно строить адаптеры между различными интерфейсами. Но доклад содержал слишком много информации для ограниченного времени, поэтому говорил он очень быстро, что уменьшало воспринимаемость информации.

После обеда был доклад Александр Кошелев "Python и Django - платформа для фрилансера". Доклад хорошо построенный, легко воспринимаемый непитонистами. Но про него можно сказать: вместо Python и Django можете подставить свой любимый язык и фреймворк.

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

Итого: Exception - интересное и полезное мероприятие, по пока это в большей мере касается питонистов. Надеюсь, что следующий раз Python уже не будет доминировать, а не то не пойду ;)

Еще отзывы можно почитать здесь.

Read More...

четверг, 6 марта 2008 г.

Китайские тестеры

Китайские тестеры хуже индусских девелоперов (c) spk

Read More...

среда, 5 марта 2008 г.

ORA-00942: Table or View Does Not Exist Oracle Error

Туплю... Через оракловый клиент сделал таблицу. После того, как прописал ее в апликухе, апликуха начала валиться с ошибкой "ORA-00942: Table or View Does Not Exist Oracle Error". Оказалось забыл закомитить. Закомитил - таже ошибка. Потратил кучу времени, оказалось все просто - оракловый клиент заходил под других юзером, у которого больше прав. Все стало на свои места, как только добавил:

ЗЫ: пошол учить матчасть...

Read More...

вторник, 4 марта 2008 г.

Флешмоб: 5 инструментов

Получил эстафету 5 инструментов - прям блог-флешмоб какой-то :)

И так, что я устанавливаю в первую очередь или проверяю установлено ли:

1. Far (mc) и реже Total Commander (однажды решил полность перейти на него, но постоянно об этом забываю в пользу Far ;) ).

2. Firefox (Google Notebook, Foxmarks Bookmark Synchronizer, Save Session - плагинов к нему много, но постоянно одни приживаются, другие отмирают, а эти 3 остаются).

3. Lingvo - без ангилйского никуда, а все не запомнишь.

4. Google и Google Notebook - первый для поиска, второй для кратких заметок.

5. Notepad++ (есть табы, много вариантов подсветок и плагинов), vim (это Редактор с большой буквы).

Все описанное выше - "непрограммерский" софт, но помагает мне работать эффективно и как программисту и как обычному пользователю.

Read More...

воскресенье, 24 февраля 2008 г.

Some shell tricks

The Definitive Guide to Bash Command Line History
Can you get cp to give a progress bar like wget?

Read More...

суббота, 23 февраля 2008 г.

Вчера снова выпал снег

Причем на этот раз его выпало много, машину пришлось откапывать.








Read More...

пятница, 22 февраля 2008 г.

Оптимизм

У него есть игрушка - он скоро умрет
Пахнет летним дождем - кто-то только что умер...
(с) Летов

Read More...

Не нравится киевское метро, попробуй поездить в нью йоркском

Что бы не разачароваться в Нью Йорке с самого начала, лучше как можно дольше воздерживаться от поездок в местном сабвее. 2 американских рубля за вход - это конешно дороговато, но не стоит забывать, что это Нью Йорк. Безумное количество станций, веток и расположение всего этого - это скорее всего дело привычки, достаточно выучить наиболее необходимый кусок. То, что на одном и том же пероне можно сесть на разные поезда, которые и дальше будут ити по одной ветке, но останавливаться на разных станциях - это тоже в принципе нормально. Нормально даже то, что сабвей - мрачное, грязное, вонючее место (если познакомиться с NY поближе, понимаеш, что другого ожидать и не следует).


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

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

Хотя мне могут возразить: "Не нравится нью йоркское метро, попробуй поездить токийском".

Read More...

четверг, 14 февраля 2008 г.

Там, где нельзя фотографировать

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



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


Read More...

Принстон - мечта студента

Принстон - небольшой городок (примерно 15 тысяч населения) недалеко от Филадельфии. В этом городке находится один из красивейших университетов мира и один старейших в США. Помимо этого он один из самых дорогих в США, обучение тут стоит 30-40 тыс. в год (за точность этих цифр не ручаюсь, источник ОБС). Поэтому учится тут сможет далеко не каждый, а вот приехать посмотреть как учатся другие стоит, при этом с собой обязательно иметь фотоаппарат и веревку, которой можно привязывать нижнюю челюсть :) Я не знаю какие кого они там учат и какие знания вкладывают в их головы, но тем условиям, в которых все это происходит, я думаю могут позавидовать студенты самых престижных отечественных вузов.

Фото без коментариев (единственное, что можно сказать, что почти все здания - это студенческие общаги).
























Read More...

среда, 13 февраля 2008 г.

Не хорошо смеяться над другими

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

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

--- UPDATED ----
фото следующего дня:

Оттаявшая из под снега машина


Пробка на выезде из гостиницы


Остатки снега на дороге

Read More...

воскресенье, 10 февраля 2008 г.

Поездка на юг

1000 километров в день на машине - это реально! Только что вернулся из поездки на юг, длинной 680 миль (чуть больше 1000 км), целью которой был мост-тунель через Чисапикский залив. Чем он замечателен - этот 37-ми километровый мост построен буквально в океане и для того, что бы не препятствовать судоходству, в двух местах он переходит в тонель по дну залива. Длина каждого из тонелей - 1 миля. На самом деле, это даже не мост, а два моста с движением в разные стороны, которые сходятся на суше и возле тонелей.


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




Не только чудо-мостом была интересна поездка. Интересно было наблюдать как живут люди в других штатах. Чем дальше от Нью Йорка, тем больше жизнь не похожа на американскую мечту. В этом плане, Нью Джерси идеальный штат для жизни (из виденных мною). Но вот уже в Делаваре и Мериленде мечта довольно часто остается мечтой - обшарпаные дома, в некоторых заколоченны окна, намного больше старых машин-развалин, машин и домов с табличкой "For sale", и, что меня больше всего поразило, целые поселки, где люди живут в трейллерах и каких-то не очень больших контейнерах. Ошущение упадка и безисходности.



Но вот мы переехали мост и попали в сказку - штат Виржиния, городок Виржиния Бич. Игрушечные домики на берегу океана в перемешку с лесом, на улицах растут пальмы, люди ходят в футболках и шортах (утром мы выежали, кутаясь в зимние куртки, а машина была покрыта инеем), ездят шикарные машины, большими группами катаются байкеры, люди гуляют по пляжу... Как на Маями :) Как же мало времени у нас там было!!!




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


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


Read More...

суббота, 2 февраля 2008 г.

Пару слов о Нью-Йорке



Нью-Йорк произвел на меня огромное впечатление. С одной стороны, я увидел все, о чем раньше мог только слышать: Бродвей, Тайм Сквер, 5-е авеню, Рокфеллер центр, статую Свободы, Чайнатаун (это было одним из первых мест, куда я отправился) и много-много еще. С другой стороны, город оказался неожиданно красивым. Каждый небоскреб отличается от друго. Между небоскребами уютно расположились старые дома, этажей по 5 в высоту. Постоянно попадаются костелы, парки, фонтаны. В центре Манхеттэна находится огромный парк. Сам Манхэттен устроен очень просто – он разделен на мелкие квадраты-кварталы улицами (идут поперек острова) и авеню (идут вдоль острова). Именуются улицы и авеню тоже просто: 1-е авеню, 2-е авеню,..., 1-я улица, 2-я улица... . Между ними длинной колбасой извивается Бродвей.


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


Вообще, об этой городине писать можно много. А так как времени пока не хватает, то ограничусь фотографиями (“А теперь слайды”).

Паром из Стэйтэн Айланда до Манхэттена



Статуя Свободы (вид с парома)



Памятник трагедии 11 сентября



Какой-то небоскреб



Тут тоже есть чем-то недовольные



Empire State Building - самое высокое здание в NY



Вид с самого высокого здания



Возле Рокфеллер центра



Еще один небоскреб



Кладбище



Собор Тринити, вид с Wall street


Read More...