Aрхитекторы

Если бы архитекторы работали как веб дизайнеры
Итоги конкурса «Трудный подросток или Клиент прав не всегда».
Победительница конкурса лишь исправила слово «сайт» на «дом», но как красиво получилось : )

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

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

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

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

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

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

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

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

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

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

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

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

   PPS. Возможно, мне нужен не дом, а автоприцеп для путешествий. Если это так, пожалуйста, сообщите мне об этом как можно скорее.

Рубрика: О наболевшем | Комментарии к записи Aрхитекторы отключены

Про разработку информационных систем…

c форума sql.ru про разработку информационных систем…

   …А вообще, я очень хочу, чтобы наша профессия со временем стала такой же инженерной дисциплиной, как, например, строительство
— вам нужно здание? Извольте заплатить за проект, а потом за возведение, или покупайте (арендуйте) готовое, но тут уж не выдвигайте требований пристроить к нему еще 30 этажей. Изволили построить времянку, а теперь хотите ее превратить в доменный цех? нет проблем — СНОСИМ временку и строим цех. Через пять лет вам потребуется переделать цех в аэропорт? Это ваши трудности — х*й в голове медицина бессильна. Вы никогда не задумывались почему в IT такой процент проваленных проектов (представьте себе такой процент например в автомобилестроениии)? А потому, что делают их не в рамках инженерного подхода, а вопреки ему….
   И заметьте, никто не кричит «Судостроители пи…сы не хотят переделать речной трамвайчик в ледокол».

Рубрика: О наболевшем | Комментарии к записи Про разработку информационных систем… отключены

Вакансия: водитель

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

   Вакансия: водитель.

   Требования: профессиональные навыки в управлении легковыми и грузовыми автомобилями,троллейбусами,трамваями, поездами
метрополитена и фуникулера, экскаваторами и бульдозерами, спецмашинами на гусеничном ходу, боевыми машинами пехоты и современными
легкими/средними танками, находящимисяна вооружении стран СНГ и НАТО. Навыки раллийного и экстремального вождения обязательны.
Опыт управления болидами «Формулы-1» — приветствуется. Знания и опыт ремонта поршневых и роторных двигателей, автоматических и
ручных трансмиссий, систем зажигания, антиблокировочных систем, навигационных систем и автомобильных аудиосистем ведущих
поизводителей — обязательны. Опыт проведения кузовных и окрасочных работ — приветствуется. Претенденты должны иметь сертификаты
Mercedes, BMW, а также справки об участии в крупных международных ралли не более чем двухлетней давности.

   Зарплата: 1500-2500 рублей, определяется по результатам собеседования.

Рубрика: О наболевшем | Комментарии к записи Вакансия: водитель отключены

Плагин для SMARTY

Целью данной статьи является показать, как пишутся пользовательские функции для SMARTY.

   Допустим, требуется функция, возвращающая значения из параметра в случайном порядке. Насколько я знаю, в стандартном наборе SMARTY такой нет.

   Пути к функциям SMARTY храница в свойстве plugins_dir объекта SMARTY.
Это массив, пишем так:


	...
	$smarty->plugins_dir[] = 'относительный или абсолютный путь к самописным функциям';
	...

   Рекомендую не хранить пользовательские функции в папке со стандартными. Это облегчит обновление SMARTY. Далее так:


	...
	<img class="{rand values=''left,center,right''}" src="..." alt="..." />
	...

   Собственно, {rand} — новая функция. values — её параметр.
Далее в папке, добавленой в plugins_dir, создаём файл function.rand.php. Почему "function" и "rand" — думаю, понятно.
Его содержимое:


<?php
/**
 * Smarty plugin
 * @package Smarty
 * @subpackage plugins
 */

/**
 * Smarty {rand} function plugin
 *
 * Type:     function
 * Name:     rand<br/>
 * Date:     August 30, 2008<br/>
 * Purpose:  random return given values<br/>
 * Input:
 *         - values = comma separated list of values to
 *         - delimiter = the value delimiter, default is ","
 *
 * @author Tsapenko Serghey aka Nck
 * @version  1.0
 * @param string
 * @return string
 */
function smarty_function_rand($params){
	$values = (empty($params['values'])) ? 'default' : $params['values'];
	$delimiter = (empty($params['delimiter'])) ? ',' : $params['delimiter'];

	if ($values == 'default')
		return null;
	$values = explode($delimiter, $values);
	$rand = array_rand($values);
	return $values[$rand];
}?>

   Коментарии необязательны (об этом лучше никому не говорить), но считаются хорошим тоном.
$params — массив, передаваемый SMARTY в функцию, содержащий параметры из шаблона.
Если параметр values отсутствует — не возвращаем ничего (return null).
   Далее, разбиваем $values в массив функцией explode
и возвращаем случайный элемент массива.
Вот и всё.

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


	...
	{rand values="itiltleft,itiltnone,itiltright" assign="rand_value"}
	<img class="instant {rand_value}" src="..." alt="..." />
	...

   Код выглядет так:


<?php
/**
 * Smarty plugin
 ...
 * @return string
 */
function smarty_function_rand($params, &$smarty){
	$values = (empty($params['values'])) ? 'default' : $params['values'];
	$delimiter = (empty($params['delimiter'])) ? ',' : $params['delimiter'];
	$var = (empty($params['assign'])) ? 'default' : $params['assign'];

	if (($values == 'default') || ($var == 'default'))
		return null;
	$values = explode($delimiter, $values);
	$rand = array_rand($values);
// Смотреть Здесь !
	$smarty->assign($var, $values[$rand]);
	return null;
}?>

   Тоже ничего сложного. В параметрах функции добавилась ссылка на объект SMARTY.
Из массива $params получаем значетие параметра assign и стандартным способом
     $smarty->assign($var, $values[$rand]);
её назначаем. Вот собственно и всё.

Рубрика: PHP | 2 комментария

Создание пользовательских обвёрток файловых функций

В этой статье будет расказано как создавать пользовательские обвёртки файловых функций. Сделаю я это на примере парсера для Atom.
Так-же рекомендую обратится к первоисточнику.

   Вводные данные:

  • Обвёртка (wrapper) позволяет расширить стандартные файловые функции (fopen(), readdir()…) для работы с разнообразными протоколами и
    типами данных. Использовать их просто: вызов fopen(‘http://www.google.com’); использует обвёртку "http"
    Посмотреть список системных обвёрток можно здесь: http://php.net/manual/en/wrappers.php.

  • Atom — это основанный на XML формат, предназначенный для новостных лент, анонсов статей и так-далее.
    От RSS отличается, но служит для тех-же целей. Как-правило, даже если используют Atom всеравно пишут RSS.
    И собственно Atom-файл:

    <?xml version="1.0" encoding="utf-8"?>
    <feed xmlns="http://www.w3.org/2005/Atom">
    	<title> Feed Title </title>
    	<link href=" http://yourwebsite.com/"/>
    	<updated>2003-12-13T18:30:02Z</updated>
    	<author>
    		<name>Your Name</name>
    	</author>
    	<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
    	<entry>
    		<title>Article Title</title>
    		<link href=" http://yourwebsite.com/articlelink.html "/>
    		<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
    		<updated>2003-12-13T18:30:02Z</updated>
    		<summary>Some text.</summary>
    	</entry>
    	<entry>
    		<title>Sports</title>
    		<link href=" http://yourwebsite.com/sportslink.html "/>
    		<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344e45ab90</id>
    		<updated>2003-12-14T13:30:55Z</updated>
    		<summary>Some text.</summary>
    	</entry>
    </feed>

   Описание:
bool stream_wrapper_register(string $protocol, string $classname)
— регистрирует пользовательскую обвёртку. Возвращает true в случае успеха и false в противном случае.
Если обвёртка уже существует, то функция ее не переопределяет и возвращает false. В этом случае нужно делать так:

//Удаляем существующую обвёртку
stream_wrapper_unregister('http');

...

//Регистрируем свою
stream_wrapper_register('http', 'CustomHTTP');

//Здесь используем свою обвёртку
...

//Востанавливаем предыдущую обвёртку
stream_ wrapper_ restore('http');

bool stream_wrapper_unregister(string $protocol)
bool stream_wrapper_restore(string $protocol)
Первая функция удаляет существующую обвёртку, вторая — востанавливает удаленную раннее обвёртку.
Обе функции возвращают true в случае успеха и false в противном случае.

В класе обвёртке нужно определить методы для файловых функций.
Они должны быть определены именно так, как указано ниже. Шаг влево, шаг вправо карается багами!
bool stream_open(string $path, string $mode, int $options, string $opened_path)
   Этот метод вызывается сразу после открытия потока функцией fopen().
   $path — имя файла, переданоё в fopen().
   $mode — режим открытия файла из fopen().
   $options — содержит дополнительные флаги, переданные системой.
Опции соеденены через OR.
     STREAM_USE_PATH — если $path содержит относительный путь,
указывает на поиск ресурса с использованием include_path
     STREAM_REPORT_ERRORS — если флаг установлен, метод несет ответственность за установку ошибок
через trigger_error(), в противном случае метод не должен выставлять никаких ошибок.
   $opened_path — если ресурс открыт успешно и в $options установлен
флаг STREAM_USE_PATH, метод должен вернуть сюда полный путь к открытому ресурсу.
void stream_close(void)
   Метод вызывается при закрытии потока, используя fclose().
string stream_read(int $count)
   Метод вызывается при использывании fread() и fgets().
Метод должен вернуть не более $count байт, начиная с текущей позиции файлового указателя.
Если байти закончились — нужно вернуть FALSE. Так-же нужно сместить файловый указатель на количество успешно прочитаных байт.
Далее кратко.
bool stream_eof(void) — для feof();
int stream_tell(void) — для ftell();
bool stream_seek(int $offset, int $whence) — для fseek();
bool stream_flush(void) — для fflush();
array stream_stat(void) — для fstat();
bool unlink(string $path) — для unlink() PHP >= 5.0.0;
bool rename(string $path_from, string $path_to) — для rename() PHP >= 5.0.0;
bool mkdir(string $path, int $mode, int $options) — для mkdir() PHP >= 5.0.0;
bool rmdir(string $path, int $options) — для rmdir() PHP >= 5.0.0;
array url_stat(string $path, int $flags) — для rmdir();

bool dir_opendir(string $path, int $options) — для opendir();
   Все функции ниже работают посе dir_opendir().
string dir_readdir(void) — для readdir() ;
bool dir_rewinddir(void) — для rewinddir();
bool dir_closedir(void) — для closedir();

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

<?php
function dump($aData){
	echo '<pre>';
	print_r($aData);
	echo '</pre>';
}

class AtomStreem{
	private $handler;
	private $raw_data = array();
	private $data = array();

	private function _GetEntryes(){
		$i = 0;// Счётчик елементов
		$entry = false;
		foreach ($this->raw_data as $idx => $row) {
			if (strpos($row, '<entry>') !== false)
				$entry = true;
//			Начало элемента
			if (strpos($row, '</entry>') !== false){
				$entry = false;
				$i++;
			}
//			Конец элемента
			if ((strpos($row, '<title>') !== false) && $entry){
//				Если в строке есть "<title>" и строка в элементе
				$row = str_replace('<title>', '', $row);
				$row = str_replace('</title>', '', $row);
				$row = trim($row);
//				Обрезаем всё лишнее
				$this->data[$i]['title'] = $row;
				unset($this->raw_data[$idx]);
//				Удаляем обработанную строку
			}
			if ((strpos($row, '<link ') !== false) && $entry){
				$row = str_replace('<link href="', '', $row);
				$row = str_replace('"/>', '', $row);
				$row = trim($row);
				$this->data[$i]['link'] = $row;
				unset($this->raw_data[$idx]);
			}
			if ((strpos($row, '<id>') !== false) && $entry){
				$row = str_replace('<id>', '', $row);
				$row = str_replace('</id>', '', $row);
				$row = trim($row);
				$this->data[$i]['id'] = $row;
				unset($this->raw_data[$idx]);
			}
			if ((strpos($row, '<updated>') !== false) && $entry){
				$row = str_replace('<updated>', '', $row);
				$row = str_replace('</updated>', '', $row);
				$row = trim($row);
				$this->data[$i]['updated'] = $row;
				unset($this->raw_data[$idx]);
			}
			if ((strpos($row, '<summary>') !== false) && $entry){
				$row = str_replace('<summary>', '', $row);
				$row = str_replace('</summary>', '', $row);
				$row = trim($row);
				$this->data[$i]['summary'] = $row;
				unset($this->raw_data[$idx]);
			}
		}
	}

	private function _GetInfo(){
//		Обрабатываем остатки данных
		foreach ($this->raw_data as $row) {
			if (strpos($row, '<title>') !== false){
				$row = str_replace('<title>', '', $row);
				$row = str_replace('</title>', '', $row);
				$row = trim($row);
				$this->data['title'] = $row;
			}
			if (strpos($row, '<link href="') !== false){
				$row = str_replace('<link href="', '', $row);
				$row = str_replace('"/>', '', $row);
				$row = trim($row);
				$this->data['link'] = $row;
			}
			if (strpos($row, '<updated>') !== false){
				$row = str_replace('<updated>', '', $row);
				$row = str_replace('</updated>', '', $row);
				$row = trim($row);
				$this->data['updated'] = $row;
			}
			if (strpos($row, '<name>') !== false){
				$row = str_replace('<name>', '', $row);
				$row = str_replace('</name>', '', $row);
				$row = trim($row);
				$this->data['name'] = $row;
			}
			if (strpos($row, '<id>') !== false){
				$row = str_replace('<id>', '', $row);
				$row = str_replace('</id>', '', $row);
				$row = trim($row);
				$this->data['id'] = $row;
			}
		}
	}

	private function _Parce(){
		$this->_GetEntryes();
		$this->_GetInfo();
	}

	/**
	 * Функция для fopen()
	 *
	 * @param string $path
	 * @param string $mode
	 * @param int $options
	 * @param string $opened_path
	 * @return bool
	 */
	public function stream_open($path, $mode, $options, $opened_path){
		$_path = parse_url($path);
		$_path = $_path['host'] . $_path['path'];
//		Предыдущее 2 строчки извлекают из строки $path сщбственно путь,
//		отбрасывая схему ("atom://" в нашем случае).
		$this->handler = fopen($_path, $mode);
		return true;
	}

	/**
	 * Функция для fgets()
	 *
	 * @param int $count
	 * @return string
	 */
	public function stream_read($count){
		while (($row = fgets($this->handler)) !== false){
//		($row = fgets($this->handler)) !== false - присваивание в условии - плохой тон.
//		Дедаем из присваивания условие
			$this->raw_data[] = $row;
		}
//		Помещаем содержимое файла в свойство $this->data.
		$this->_Parce();
//		Парсим содержимое файла
		return serialize($this->data);
//		serialize() - потому-что функция должна возвращать string
	}

	/**
	 * Функция для fclose()
	 */
	public function stream_close(){
//		Здесь освобождаем ресурсы
		fclose($this->handler);
		unset($this->handler);
		unset($this->raw_data);
		unset($this->data);
	}

	/**
	 * Функция для feof()
	 * У функции fgets(), в отличии от fread() параметр $length необязателен.
	 * На самом деле fgets() - это цикл, вызывающий fread() с длинной 1байт и feof().
	 *
	 * @return bool
	 */
	public function stream_eof(){
		if (count($this->data))
			return true;
		return false;
	}
}

stream_wrapper_register('atom', 'AtomStreem');
// Регистрируем обвёртку
$fp = fopen('atom://./atom.xml', 'rb');
dump(unserialize(fgets($fp)));
// unserialize() - смотри метод stream_read()
fclose($fp);
?>

Результат работы:

Array
(
    [0] => Array
        (
            [title] => Article Title
            [link] => http://yourwebsite.com/articlelink.html
            [id] => urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a
            [updated] => 2003-12-13T18:30:02Z
            [summary] => Some text.
        )

    [1] => Array
        (
            [title] => Sports
            [link] => http://yourwebsite.com/sportslink.html
            [id] => urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344e45ab90
            [updated] => 2003-12-14T13:30:55Z
            [summary] => Some text.
        )

    [title] => Feed Title
    [link] => http://yourwebsite.com/
    [updated] => 2003-12-13T18:30:02Z
    [name] => Your Name
    [id] => urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6
)

Вот, собственно, и всё.

Рубрика: PHP | 6 комментариев