Обновить

Удалённая компиляция TeX

Возникла в кои-то веки необходимость поработать с LaTeX.
Вариант оторваться от eeePc и дивана в пользу стационарного компа не рассматривается в силу непреодолимых обстоятельств. Лень, если яснее выражаться.

Первый позыв — ставим texlive из репозитория и работаем.

$ sudo aptitude install texlive texlive-lang-cyrillic
...
Необходимо получить 128MБ архивов. После распаковки 272MБ будет занято.


Да ну, нафиг. Жалко место, системный раздел ощутимо нерезиновый.

Значит, надо удалённо компилировать TeX в pdf, посещает меня гениальная мысль. Благо ssh между Старшим и Младшим братьями навострён довольно давно, с ключевой авторизацией и всеми делами.

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

haXe 2.04 c поддержкой C++

Благодаря напряженной работе Hugh Sanderson haXe теперь поддерживает С++ платформу.

Это значит, что можно компилировать любую haXe программу под С++ и, таким образом, получать производительность одного из самых быстрых языков. Это открывает массу возможностей, таких например, как запуск haXe программ на iPhone.

Чтобы использовать новую возможность, нужно проставить таргет -cpp, но перед этим следует установить библиотеку hxcpp:

haxelib install hxcpp

Пишем простую программку на haXe:

class HelloWorld {
static function main() {
trace("Hello World, haXe!");
}
}


И компилируем:

haxe -cpp out -main HelloWorld

В итоге получим файл out/HelloWorld.exe

Также доступно C++ API.

C++ стал шестой платформой, поддерживаемой haXe:
  • Flash (для Flash Player версии <=8)
  • Flash9 (AVM2, для Flash Player версий>= 9)
  • Javascript
  • Neko
  • PHP
  • теперь и C++
Интересно, что будет дальше?

Микроформаты, reset.css, экскременты.

Вы не догадываетесь какая связь между этими тремя словами? Узнаете, прочитав до конца. Не торопитесь воротить нос, тут совсем не много букаФ :). Просьба к модератору: не выкидывайте эту статью, опубликуйте, пожалуйста, в песочнице. Люди, которые считают, что микроформаты и reset.css — это необходимость, посмеются над очередным «ламером» или немного задумаются. В любом случае польза будет.

Начнем с микроформатов. Цитата из википедии:

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


Другими словами ленивые программисты придумали микроформаты, которые HTML-верстальщику говорят как он должен верстать. А им (программистам) потом не придется ломать голову как это всё распарсить для нужд программы. Проведем аналогию:
ГИБДД ввело новые правила, по которым любители быстрой езды обязаны ездить на автомобилях красного цвета, женщины — на машинах розового цвета, водители с замедленной реакцией — желтый цвет, пьяницы — синий и т.д. Ездить нужно строго группами. Впереди и сзади каждой группы должен ехать грузовик с плакатом, например «Мы выпили бутылку пива».
Вас не тошнит от таких правил?

Продолжить?
Читать дальше →

Еще один пример использования WPF или заменяем MessageBox

В данной статье люди знакомые c технологией WPF не найдут ничего нового. Это всего лишь краткий обзор того, чем еще можно порадовать себя, используя данную технологию.
Все мы знаем как иногда раздражают всякого рода MessageBox-ы, они всегда вылетают как раз не к стати, сбивают нас с мысли посторонним звуком, да и выглядят ужасно. Ведь уже никто не читает что на них написано.
В этой статье я покажу вам пример того, как можно создать менее раздражающую замену стандартному MessageBox-у, используя технологию Windows Presentation Foundation.
Читать дальше →

Методика безопасного обновления баз данных

Здравствуйте, уважаемые хабралюди!

Порывшись в сети и в частности на Хабре не обнаружил ни одной темы как безболезненно и главное с 99% успеха обновлять базы данных.

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

Для того чтобы решить эти проблемы необходимо применять следующую методику:

1. Удалить все объекты(кроме таблиц)
2. Выполнить действия по обновлению структуры стаблиц, данных
3. Пересоздать все объекты(уже новой версии)

Данная методика как раз позволяет обновить БД с любой версии до последней, но возникает вопрос: как безопасно удалить все объекты?
Можно конечно написать скрипт который будет учитывать связи между объектами и удалять их в нужной последовательности. Такой подход трудоемок и при модификации БД требует корректировки скрипта удаления объектов, к тому же существует проблема с удалением рекуррентных процедур.
Лучше и быстрее избавляться от связей в процедурах пересоздав их с теми же входными и выходными параметрами, но с пустым телом. При этом зависимости пропадут сами собой.
Вот пример скрипта который как раз этим и занимается(писался и тестировался для FireBird 2.0 и выше)

Блок 1 — Пересоздаем все процедуры с пустым телом
execute block
as
declare variable lPROC_NAME varchar(31);
declare variable lPARAM_NAME varchar(31);
declare variable lPARAM_NUMBER smallint;
declare variable lPARAM_COUNT_INP smallint;
declare variable lPARAM_COUNT_OUT smallint;
declare variable lPARAM_TYPE smallint;
declare variable lTEXT varchar(5000);
declare variable lTEXT_INP varchar(2500);
declare variable lTEXT_OUT varchar(2500);
declare variable lSUB_TEXT varchar(50) = ' as begin end' ;
declare variable lFIELD_SOURCE varchar(31);
declare variable lVARIABLE varchar(100);
begin
for select P.RDB$PROCEDURE_NAME, P.RDB$PROCEDURE_INPUTS, P.RDB$PROCEDURE_OUTPUTS from RDB$PROCEDURES P
into :lPROC_NAME, :lPARAM_COUNT_INP, :lPARAM_COUNT_OUT
do
begin
lTEXT = 'create or alter procedure '||trim(:lPROC_NAME);
lTEXT_INP = '';
lTEXT_OUT = '';
if (coalesce(lPARAM_COUNT_INP,0)>0) then
lTEXT = lTEXT||'(';
if (coalesce(lPARAM_COUNT_OUT,0)>0) then
lTEXT_OUT = 'returns( ';
for
select PP.RDB$PARAMETER_NAME, PP.RDB$PARAMETER_NUMBER,
PP.RDB$PARAMETER_TYPE, PP.RDB$FIELD_SOURCE
from RDB$PROCEDURE_PARAMETERS PP
where PP.RDB$PROCEDURE_NAME = trim(:lPROC_NAME)
order by PP.RDB$PARAMETER_NUMBER, PP.RDB$PARAMETER_TYPE
into :lPARAM_NAME, :lPARAM_NUMBER,
:lPARAM_TYPE, :lFIELD_SOURCE
do
begin
lPARAM_NAME = trim(lPARAM_NAME);
lFIELD_SOURCE = trim(lFIELD_SOURCE);
select
case
when F.RDB$FIELD_TYPE = 261 then :lPARAM_NAME||' blob sub_type '||F.RDB$FIELD_SUB_TYPE||' segment size '||F.RDB$SEGMENT_LENGTH
when F.RDB$FIELD_TYPE = 14 then :lPARAM_NAME||' char('||F.RDB$FIELD_LENGTH||')'
when F.RDB$FIELD_TYPE = 40 then :lPARAM_NAME||' cstring('||F.RDB$FIELD_LENGTH||')'
when F.RDB$FIELD_TYPE = 11 then :lPARAM_NAME||' dfloat'
when F.RDB$FIELD_TYPE = 27 then :lPARAM_NAME||' double'
when F.RDB$FIELD_TYPE = 10 then :lPARAM_NAME||' float'
when F.RDB$FIELD_TYPE = 16 and coalesce(F.RDB$FIELD_SCALE,0) = 0 then :lPARAM_NAME||' bigint'
when F.RDB$FIELD_TYPE = 8 and coalesce(F.RDB$FIELD_SCALE,0) = 0 then :lPARAM_NAME||' integer'
when F.RDB$FIELD_TYPE = 7 and coalesce(F.RDB$FIELD_SCALE,0) = 0 then :lPARAM_NAME||' smallint'
when F.RDB$FIELD_TYPE = 9 then :lPARAM_NAME||' quad'
when F.RDB$FIELD_TYPE = 12 then :lPARAM_NAME||' date'
when F.RDB$FIELD_TYPE = 13 then :lPARAM_NAME||' time'
when F.RDB$FIELD_TYPE = 35 then :lPARAM_NAME||' timestamp'
when F.RDB$FIELD_TYPE = 37 then :lPARAM_NAME||' varchar('||F.RDB$FIELD_LENGTH||')'
when coalesce(F.RDB$FIELD_SCALE,0) <> 0 then :lPARAM_NAME||' numeric('||F.RDB$FIELD_PRECISION||','||iif(F.RDB$FIELD_SCALE<0, -F.RDB$FIELD_SCALE, F.RDB$FIELD_SCALE)||')'
end
from RDB$FIELDS F
where F.RDB$FIELD_NAME = :lFIELD_SOURCE
into :lVARIABLE;
if (lPARAM_TYPE = 0) then --входные параметры
begin
lTEXT_INP = lTEXT_INP||' '||lVARIABLE||',';
if (lPARAM_NUMBER = lPARAM_COUNT_INP - 1) then
lTEXT_INP = substring(lTEXT_INP from 1 for char_length(lTEXT_INP) - 1)||')';
end
else --выходные переметры
begin
lTEXT_OUT = lTEXT_OUT||' '||lVARIABLE||',';
if (lPARAM_NUMBER = lPARAM_COUNT_OUT - 1) then
lTEXT_OUT = substring(lTEXT_OUT from 1 for char_length(lTEXT_OUT) - 1)||')';
end
end
lTEXT = lTEXT||coalesce(lTEXT_INP,'')||' '||coalesce(lTEXT_OUT,'')||lSUB_TEXT;
execute statement lTEXT;
end
end;


Блок 2 — Удаляем все процедуры

execute block
as
declare variable lPROC_NAME varchar(31);
begin
for select P.RDB$PROCEDURE_NAME from RDB$PROCEDURES P
into :lPROC_NAME
do
execute statement 'drop procedure '||:lPROC_NAME;
end;

Все остальные объекты удаляются аналогично как в блоке 2.
Дальше нам необходим набор из скриптов(например пересоздения ВСЕХ представлений, внешних функций и процедур) в которых будет храниться актуальная на данный момент информация.
Запускаем их и получаем БД самой последней версии.
P.S. Все скрипты тестились неоднократно и прекрасно работают на FireBird, немного поработать напильником и можно адаптировать под любую СУБД.

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

Реализация Ajax в ASP.NET Web Form

Привет всем!

Хочу рассказать о том как передать и обработать информацию на сервере не перегружая страницу. В ASP.NET уже существуют такие инструменты в виде UpdatePanel и т.д, которые дают большие возможности, причем не имея абсолютно никаких знаний. Достаточно поиграться с этими инструментами полчаса и вуаля, готово! Но как показал мне горький опыт вместо того чтобы ускорить работу, все стало еще больше тормозить (использовался дешевый windows хостинг).

Итак начнем.

идем сюда и качаем библиотеку jquery (можно использовать и другие фреймворки, по вкусу)

создаем новый сайт и самую простую форму
<input id="some_text" type="text" /><input id="some_button" type="button" value="OK" />
<div id="some_div"></div>



не забываем подключить библиотеку jquery
<script src="jquery-1.3.2.js" type="text/javascript"></script>


теперь сам клиентский код который сначала отправит данные на сервер а потом их получит
<script language="javascript">
  
   $(document).ready(function() {
    $('#some_button').click(function() {
    send();
    
   });
});

function send()
{
$.get("some_handler.ashx", { text: $("#some_text").val()},
 function(data){
  $("#some_div").html(data);
 });
}
  </script>




с помощью метода GET мы отправляем данные с текстового поля в some_handler.ashx.
  1. using System;
  2. using System.Web;
  3.  
  4. public class some_handler : IHttpHandler {
  5.   
  6.   public void ProcessRequest (HttpContext context) {
  7.    
  8.     string somecomment = context.Request["text"];
  9.     context.Response.Write(some_class.some_method(somecomment));
  10.   }
  11.   public bool IsReusable {
  12.     get {
  13.       return false;
  14.     }
  15.   }
  16.  
  17. }



Дальше нужно создать класс some_class со статическим методом some_method который будет обрабатывать полученные данные
  1. public class some_class
  2. {
  3.   public static string some_method(string some_string)
  4.   {
  5.     some_string = "Привет <b>" + some_string + "</b> с сервера!!!";
  6.     
  7.     return some_string;
  8.   }
  9. }



Смотрим что получилось:
image

Pivot — как установить и заставить работать работать на не EN-US windows

Многие прочитали пост Pivot — инновационный путь работы с данными, некоторые запросили код, который присылают достаточно быстро (за несколько часов). Но при попытке установить программу на русскую версию windows начинаются проблемы.
image
Ошибка которая возникает на стадии установки
Решается все довольно просто
Заходим в панель управления -> язык и региональные стандарты
image
рис.1 выбираем формат Английский(США)
image
рис.2 далее в расположении ставим США
image
рис.3 и наконец меняем язык системы на Английский (США)

Перезагружаемся!

Это все нужно для того чтобы установщик сформировал правильный POST-запрос
Action 8:59:52: ValidateKeyCode.
Action start 8:59:52: ValidateKeyCode.
Custom Action Log: Validating keycode 8180 E827 9D04 C529
MSI (c) (98!B8) [08:59:52:951]: PROPERTY CHANGE: Modifying ValidationResult property. Its current value is '0'. Its new value: '-1'.
Custom Action Log: In ValidateKeyCodeHelper, decrementKey is False, KeyCode is 8180 E827 9D04 C529
Custom Action Log: CleanKeyCode result is 8180E8279D04C529
Custom Action Log: IsProperlyFormated result is True
Custom Action Log: In ValidateKeyCodeHelper, KeyCode property formatted
Custom Action Log: In ValidateKeyCodeWithServer, decrementKey is False, KeyCode is 8180E8279D04C529
Custom Action Log: In ValidateKeyCodeWithServer, httpRequest created
Custom Action Log: In ValidateKeyCodeWithServer, postData is {"keyCode":"8180E8279D04C529","decrementInstallCount":"false"}
Custom Action Log: In ValidateKeyCodeWithServer, validationUrl is https://www.getpivot.com/Activation/KeycodeService.svc/ValidatePivotKeyCode
Custom Action Log: In ValidateKeyCodeWithServer, request complete
Custom Action Log: In ValidateKeyCodeWithServer, request successful, response was 1
Custom Action Log: ValidateKeyCodeWithServer, result is 1
Custom Action Log: ValidateKeyCodeHelper result is 1
MSI (c) (98!B8) [08:59:54:141]: PROPERTY CHANGE: Modifying ValidationResult property. Its current value is '-1'. Its new value: '1'.
Custom Action Log: Validation complete, result is 1
Action ended 8:59:54: ValidateKeyCode. Return value 1.

Так выглядит кусок лога который можно получить командой msiexec /i ваш_пакет.msi /lv* log.txt KEYCODEDEBUG=1, на месте false не должно быть «ложь», «faux» и т.д.

После того как вы установите Pivot, вам захочется вернуть настройки назад, но когда вы это сделаете Pivot перестанет запускаться. Для того чтобы вернуть его к жизни выставьте формат «Английский(США)» как на рис.1

Официальная позиция (перевод)


… Я согласен что данное решение подходит далеко не всем пользователям. Мы выясняем сколько пользователей заинтересовано в многоязычной версии. В текущем релизе это просто ограничение в программе… proof

Так что качайте, устанавливайте и создавайте треды с просьбой локализовать pivot.

p.s. код из лога можно использовать еще раз 9

Admin Runner — решаем проблему «запуска от имени» в IE7, IE8

Приветствую! Я тружусь администратором на благо нашей родины в крупном государственном медицинском учреждении.
После появления у нас на работе компьютеров с IE7 и IE8, мы, как и многие столкнулись с проблемой запуска эксплорера и нужных оснасток от имени администратора. Классический runas перестал работать =( Т.е. при запуске из командной строки — не открывается вообще ничего, а при запуске Internet Explorer через контекстное меню «Запуск от имени...» открывается только сам IE. В результате, чтобы выполнить какие-либо административные действия, приходится завершать сеанс и залогиниваться под администратором. Что долго и неудобно.

На помощь мне пришла простая и очень удобная программка AdminRunner, написанная моим знакомым Крюковым Алексеем Анатольевичем.
С его позволения расскажу и покажу как она работает.
Читать дальше →

Postgresql replication.

Тихо и незаметно подкралась ко мне задача оптимизировать работу своих серверов. Долго я её откладывал и совсем не хотел ей заниматься, НО настало время когда нужно было что то делать. Итак первым делом мы в нашем отделе решили, что наверное как то неразумно использовать на каждом своём сервере Postgresql сервер, и решили вынести всё на отдельную мощную машинку.
Итак заказали мы машинку, долго её ждали, и жутко обрадовались когда эта самая машинка поселилась в нашей серверной. Поставили мы на неё «базу» и начали тестировать развернув по копии базы каждого из имеющихся у нас проектов. Вроде всё работало положительно, НО тут образовался вопрос: а что делать если вдруг машинка упадёт ?!
После долгих споров было решено для резервирования приобрести еще один сервер. И опять мы ждали, пока не пропишется у нас в серверной и вторая машинка. И вот это случилось!
Теперь нужно было решить каким способом мы будем эти самые данные резервировать, да еще и так чтобы данные на одном сервере были всегда актуальны, а именно чтобы в любой момент времени данные на обеих машинах были абсолютно идентичны. Порылись в интернете и нашли 3 живых проекта, реализующих репликацию postgres.
Итак первый из них был Pgpool. Поставить и сконфигурировать его особого труда не составило. Но сразу не понравилось что pgpool не поддерживает md5 шифрование в режиме репликации — это сразу очень сильно покоробило. Да и работал он всё таки не так как нам бы хотелось на тот момент. И было решено отказаться от данного решения.
Вторым способом был избран Slony-I из за большого количества доступной документации. Хотя сразу нам не понравилось что всё как то сложно и геморно. Но ничего, нам не привыкать. Поставили настроили, заработало! И думали что вот оно решение которое мы так долго искали, даже уже написали какие то скрипты для автоматического добавления баз данных и таблиц в реплецируемый кластер, ан нет и тут оказалось не всё так гладко. Во первых когда пришло время обновления одного из проектов, мы в ужасе узнали что slony-I не умеет DDL, а при обновлении проекта как раз требовалось создать новые колонки в одной из таблиц. Ну что ж, подумал я, значит проведем изменения в базе сначала на мастер сервере, а потом уже и на слэйве и всё у нас будет реплецироваться замечательно. Ан нет, не тут то было! Оказывается Slon-I при старте репликации успешно заблокировал таблицы на slave сервере и проведя успешные изменения таблицы на мастер сервере, на слэйве нам это сделать не удалось, после этого было найдено решение: slony.info/documentation/ddlchanges.html. Но нам показалось что использовать его постоянно( а обновления у нас процедура довольно частая ) это слишком неудобно и не комфортно. И тут было принято решение, которого я сильно опасался по причине отсутствия на тот момент хоть мало мальски внятной документации у проекта. А именно решено было попробовать skytools(londiste) от Skype.
Сейчас уже можно сказать, что зря я наверно тогда так сильно волновался по поводу Londiste. Всё оказалось очень просто, а что, наверное, самое главное работоспособно и надёжно. Итак установка:
Сразу скажу что мы используем CentOs на своих серверах. Сначала необходимо всё правильно поставить. SkyTools есть в репозиториях постгреса для CentOs, но проблема заключается что в этом пакете не включены модули дополнительные, а именно Pgq_LowLevel. Поэтому сделал следующее:
Скачал последнюю версию skytools с сайта, сконфигурил, скомпилировал, и взял оттуда лишь модули для питона Pgq_LowLevel, затем поставил пакет( благо версии пакета в репозитории и модулей совпали) и скопировал модули pgq_lowlevel.so, pgq_triggers.so, logtriga.so в /usr/lib/pgsql/.
Всё дальше можно переходить к репликации.
Теперь все нижеследующие действия будут проходить от пользователя postgres и только на master сервере, но нужно учесть, что на слэйв сервер был доступ для пользователя владеющего базой данных, то есть должна выполняться команда:
psql -h slave.server.r -U your_user -d your_database

Теперь нужно установить pgqadmin. Создаём любой файл следующего содержания:
[pgqadm]
job_name = your_cluster_name
db = dbname=your_database_name

# how often to run maintenance [seconds]
maint_delay = 600

# how often to check for activity [seconds]
loop_delay = 0.1

logfile = ~/log/%(job_name)s.log
pidfile = ~/pid/%(job_name)s.pid

в моём случае это файл /etc/pgq_database_name.
Дальше «проинсталлируем» pgq для каждой конкретной базы.
$ pgqadm.py /etc/pgq_database_name install

Pапускаем pgqadm в режиме демона
$ pgqadm.py -d /etc/pgq_database_name

Создаём очередь и регистрируем консьюмер для каждой базы.
$ pgqadm.py create your_queue
$ pgqadm.py /ect/pgq_databse_name register your_queue your_consumer

Теперь когда создана очередь, мы можем начать нашу репликацию. Создаём файл /etc/londiste_your_cluster_name.ini вида:
[londiste]
job_name = your_cluster_name

provider_db = dbname=your_database
subscriber_db = dbname=your_database port=5432 host=slave.server.r user=files_testing password=your_password

# it will be used as sql ident so no dots/spaces
pgq_queue_name = your_queue

logfile = /tmp/%(job_name)s.log
pidfile = /tmp/%(job_name)s.pid

Когда файл создан запускаем londiste:
londiste.py /etc/londiste_your_cluster_name.ini provider install
londiste.py /etc/londiste_your_cluster_name.ini subscriber install

Добавляем таблицы для репликации и запустим репликацию:
londiste.py /etc/londiste_your_cluster_name.ini provider add table1 table2 table3
londiste.py /etc/londiste_your_cluster_name.ini subscriber add table1 table2 table3
londiste.py -d /etc/londiste_your_cluster_name.ini replay

Так же нужно заметить что у каждой реплицируемой таблицы должен быть Primary Key.
Вот собственно и всё. Теперь Оставалось протестировать всё это. Собственно DDL londiste так же как и Slony-I тоже не умеет, зато при репликации он не блокирует таблицы на Slave сервере и мы можем спокойно производить изменения таблиц на как на слэйве так и на мастер сервере. Был написан сценарий для capistrano(с его помощью у нас выкатываются все последние изменения и апдейты ) который проводит изменения на 2 хостах сразу. Работает всё это очень быстро. Крайне удобно всем этим управлять благодаря средствам Londiste. Добавить например таблицу или же удалить её из репликации труда особого не составляет.
После всего написал плагины для нагиоса для мониторинга репликации. Вернее даже сказать что они просто дёргают сначала из одной, а потом из другой базы количество записей в одной из таблиц и сравнивают их. Так же монитором наличие процесса londiste.py replay но это всё уже просто на всякий случай, пербоев и прерываний репликации к счастью пока не было, надеюсь не будет и впредь.
После успешного тестирования данной системы, потизоньку перетащили все базы с локальных хостов на один выделенный сервер, что принесло весьма положительный эффект и сейчас очень этим довольны.

P.S. Не ругайте сильно, если что не так, это моя первая статья на хабре.

Admin Runner — Решаем проблему «запуска от имени» в IE7, IE8

Приветствую! Я тружусь администратором на благо нашей родины в крупном государственном медицинском учреждении.
После появления у нас на работе компьютеров с IE7 и IE8, мы, как и многие столкнулись с проблемой запуска эксплорера и нужных оснасток от имени администратора. Классический runas перестал работать =( Т.е. при запуске из командной строки — не открывается вообще ничего, а при запуске Internet Explorer через контекстное меню «Запуск от имени...» открывается только сам IE. В результате, чтобы выполнить какие-либо административные действия, приходится завершать сеанс и залогиниваться под администратором. Что долго и неудобно.

На помощь мне пришла простая и очень удобная программка AdminRunner, написанная моим знакомым Крюковым Алексеем Анатольевичем.
С его позволения расскажу и покажу как она работает.
Читать дальше →

Очередной хак с min/max-width/height для ie6

Небольшая наработка которая решает проблему max и min-width в ie6. Навеяно статьей на Хабре. В для контейнеров которые используют стили min/max-width нужно задать соответственно классы ie6-width/height.

Подключаем:





Применяем:


...

Содержимое контейнера...


Код модуля:

$(document).ready(function()
{
/* хак для ie6 min-width, max-width, min-height */
if ((navigator.userAgent.toLowerCase().indexOf("msie 6") != -1) ||
(navigator.userAgent.toLowerCase().indexOf("msie 5") != -1))
{
$('.ie6-width').each
(
function()
{
var jqw_max, jqw_min;
if ( ! parseFloat(jqw_max = $(this).css('max-width')) )
jqw_max = '*';
if ( ! parseFloat(jqw_min = $(this).css('min-width')) )
jqw_min = '0';
$(this).wrap('
');
$(this).before('');
}
);
$('.ie6-height').each
(
function()
{
var jqh_min;
if ( ! parseFloat(jqh_min = $(this).css('min-height')) )
jqh_min = '0';
$(this).wrap('
');
$(this.parentNode).before('');
}
);
}
});


P.S. x.gif — картинка 1px*1px c прозразным фоном.

P.P.S. минимальна высота контейнера задается по аналогии с шириной.

JDownloader — Exception occurred java.lang.NoClassDefFoundError: Could not initialize class javax.swing.UIManager

Две недели служил мне верой и правдой замечательный менеджер закачек с файлообменников JDownloader, который работает на Java.
Но вчера он взял и не запустился Вот так вот вдруг…

3s.865 - SEVERE [jd.controlling.JDLogger(exception)] -> SEVERE Exception occurred
java.lang.ExceptionInInitializerError
at jd.gui.swing.laf.LookAndFeelController.install(Loo kAndFeelController.java:344)
at jd.gui.swing.laf.LookAndFeelController.setUIManage r(LookAndFeelController.java:207)
at jd.SplashScreen.init(Unknown Source)
at jd.Main$2.runSave(Unknown Source)
at jd.gui.swing.GuiRunnable.run(GuiRunnable.java:85)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilter s(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(U nknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarch y(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Caused by: java.lang.IllegalArgumentException: 240997 incompatible with Text-specific LCD contrast key
at java.awt.RenderingHints.put(Unknown Source)
at sun.awt.windows.WDesktopProperties.getDesktopAAHin ts(Unknown Source)
at sun.awt.windows.WToolkit.getDesktopAAHints(Unknown Source)
at sun.awt.SunToolkit.getDesktopFontHints(Unknown Source)
at sun.awt.windows.WDesktopProperties.getProperties(U nknown Source)
at sun.awt.windows.WToolkit.updateProperties(Unknown Source)
at sun.awt.windows.WToolkit.lazilyInitWProps(Unknown Source)
at sun.awt.windows.WToolkit.lazilyLoadDesktopProperty (Unknown Source)
at java.awt.Toolkit.getDesktopProperty(Unknown Source)
at javax.swing.UIManager.init(Unknown Source)
... 13 more
03s.995 - SEVERE [jd.controlling.JDLogger(exception)] -> SEVERE Exception occurred
java.lang.NoClassDefFoundError: Could not initialize class javax.swing.UIManager
at jd.gui.swing.laf.LookAndFeelController.install(Loo kAndFeelController.java:344)
at jd.gui.swing.laf.LookAndFeelController.setUIManage r(LookAndFeelController.java:207)
at jd.SplashScreen.init(Unknown Source).... more... more... more....


Снос и повторная установке не помогли… Снос виртуальной машины Java и установка последних или более старых ее версий тоже не помогли. Что же могло случиться?
Мозг пытался вспомнить, что, что же я такого мог сделать/установить/удалить что программа перестала запускаться…

Ответ оказался так банален…

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

Даёшь старому железу новую жизнь!

Недавно в руки попалась забавная железка — старый 100 ваттный усилитель Бриг. Давно хотелось улучшить и немного подправить звук идущий с компа + повысить мощность домашней стереосистемы.

Опытные экземпляры усилителя — ''Бриг-001С'' были выпущены 1975 году, а в 1976 году он был запущен в серийное производство. Выпускался усилитель до 1989 года, претерпев несколько модернизаций электрической схемы. С 1985 года на Новокаховском приборостроительном заводе ''Сокол'' выпускали УКУ (Усилительно-коммутационное устройство) — ''Барк-001-стерео'', кроме наименования схожий с описанным УКУ — ''Бриг-001-стерео''.

Этот усилитель в свое время считался одним из лучших. Он отличался очень низким уровнем шумов, малыми интермодуляционными и гармоническими искажениями, линейностью фазовой и АЧХ, чем и заинтриговал. Закипела работа. Первое, что поразило наповал — то, что он прекрасно работал и почти сразу удалось его запустить и после небольшой подстройки и проверки большей части цепей на целостность пайки были обнаружены пару деталей, которые были припаяны плохо и, со временем, просто отошли от платы. После того, как всё припаял — заработал идеально, как вчера с заводского конвейера. Звук, однако, радовал не долго — регулятор баланса безбожно хрипел и постоянно пытался выключить левый канал. Это не лезло ни в какие ворота и я подумал, что заменить его будет вообще не проблема. Не тут -то было. Мне достался экземпляр с нестандартным набором деталей. Мало того, что на радиорынке ничего найти не удалось, так ещё оказалось, что и аналогов то такого сдвоенного резистора уже давно нет. Пришлось разбирать стандартный сдвоенный резистор и вычищать его по максимуму. После 1,5 часов извращений удалось подогнать длину ползунка на левом канале, чтобы он вышел на не стертую резистивную поверхность и начал работать нормально без хрипа и скрежета.

Дальше была в основном чистка всех блоков от пыли и грязи, в процессе которой выяснилось, что транзисторы предусилителя и усилителя мощности соединены с радиаторами через прослойку из термопасты для лучшей теплопроводности. Снова поход на радиорынок, на этот раз за покупкой термопасты. На глаза попался отечественный аналог буржуйской термопасты — кремниевая паста КТП-8. По заверению продавца — «Гораздо лучше всяких зарубежных!» Штука действительно приятная в работе. Выскреб засохшую старую термопасту — заложил все новой. Эффект был заметен сразу — усилитель вообще перестал греться — радиаторы едва теплые, т.к. всё тепло мгновенно рассеивается в атмосферу.

«Ну, всё!», подумалось мне, но снова не тут-то было. Версия моего усилителя была 1976 года изготовления. Тогда был в ходу пятиштырьковый способ коммутации колонок и всего прочего оборудования с этим усилителем. Стандарт устаревший и весьма неудобный асимметричностью штекеров. Чтобы его вставить, не видя разъёма, надо потратить некоторое количество времени. «Это будет неудобно..» и вот я снова с паяльником — решился заменить один из пятиштырьковых стереовходов на стандартное гнездо под TSR (stereo) Jack 6.3mm и одну пару выходов на колонки заменить под пару Jack 6.3mm. Еще пол часа подгонки небыли потрачены зря, все заработало сразу после сборки и нареканий пока не вызывает. С заменой разъёмов подключать усилитель стало одно удовольствие — звук стал более приятным — совсем исчезли шипения и редкий скрежет контактов джеков в динамиках.

В кратце технические характеристики:

Номинальная выходная мощность на нагрузке 8 ом, Вт 2х50.
Номинальный диапазон воспроизводимых частот при неравномерности АЧХ ±0,7 дБ, Гц — 20...25.000.
Коэффициент гармоник в диапазоне частот 40...16000 Гц, % — 0,1.
Коэффициент искажений, % — 0,15.
Разделение каналов на частоте 1000 Гц, дБ — 50.
Отношение сигнал/взвешенный шум для ЛВ, дБ — 86.
Потребляемая мощность от сети, Вт 150.
Габариты, мм 452х372х118. Масса УКУ, кг 15.

УКУ ''Бриг-001-стерео'', позднее ''Бриг У-001-стерео'' предназначено для высококачественного усиления музыкальных и речевых программ с микрофона, магнитного и пьезоэлектрического звукоснимателя, тюнера, магнитофона или других НЧ сигналов. В УКУ имеется ступенчатая регулировка громкости и тембра, возможность изменения АЧХ с помощью фильтров ВЧ и НЧ, имеется система мягкого включения, исключающая неприятные щелчки при включении и выключении, защита от короткого замыкания в нагрузке, световая индикация электросети, перегрузки каналов усилителя. К УКУ можно подключить четыре АС с сопротивлением 4...8 ом, или стереотелефоны.


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

Наследование таблиц там где они не наследуются

Решила как-то одна небольшая контора написать небольшой сервис, который сразу лег посильной ношей на мои плечи. Так как проект предполагал работу с четырмя видами контента очень схожими на уровне абстракции, было принято решение использовать всю силу ООП со стороны PHP, и хотелось добиться наследования на стороне БД, как это позволяет сделать PostgreSQL. Но в ходе длительных и горячих споров было принято решение в пользу MySQL — дескать устонавливать его проще, и вообще… После нескольких доводов я сдался.

Размышления:


Конечно можно сделать совсем просто — в одной таблице объявить ВСЕ поля ВСЕХ контентов и добавить поле отвечающее за его класс, но это, на мой взгляд, не совсем удачная схема. Но при добавлении нового типа контента в систему могут возникнуть разнообразные проблемы. Как же сделать удобнее?

Что же такого хорошего в наследовании таблиц? А вот что: например у нас имеется 2 вида контента (их было 4): видео и книги. При достаточном размышлении, мы можем придти к мысли что такие параметры как заголовок, описание, рейтинг в системе, количество просмотров/скачиваний и прочую информацию мы можем вынести в базовый класс (в PHP), а вот такие параметры как напрмер количество страниц, продолжительность видео — присущи уже потомкам. Да и операции добавления/удаления и даже комментарии — вполне общие для всех типов. Однозначно — без ООП ни ногой.
Ну а что в базе данных? Мы могли бы ввести «базовую» таблицу content, в ней указать id, rating, votes, comments… а в наследуемых таблицах добавить pages/duration и остальные поля, присущие исключительно типам контента.

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

Разрешение:



Итак, этап первый: создаем базовую таблицу контента content:
  • id
  • rating
  • votes
  • comments

Добавляем таблицу комментариев comments:
  • id
  • content_id
  • text
  • author_id

Добавляем внешние ключи (comments.content_id => content.id ON DELETE CASCADE), добавляем триггеры (на добавление/удаление комментария +- content.comments)

так же создаем функцию vote(cid, uid, rating) — для изменения рейтинга контента.

Еще можно много чего сделать, но думаю этого достаточно, что бы показать идею.

Кульминация:


Создаем таблицу books. Как многие догадались — это таблица для контента типа «книга», одна будет «наследовать» таблицу content, со всеми ее (контента) вкусностями.
Но если говорить честнее (и что бы было понятнее), мы всего лишь введем такой подход, при котором одной строке в таблице книг будет однозначно ставиться в соответствие одна запись из таблицы «контент». И вот как этого добиться:
Воодим таблицу books:
  • id
  • cid
  • title
  • descr
  • pages

создаем внешний ключ (books.cid => content.id ON DELETE CASCADE), и создаем триггер, который при добавлении строки в таблицу books, создает и ставит ей в соответствие строку в таблице content:
DROP TRIGGER IF EXISTS `t_books_insert`//
CREATE TRIGGER `t_films_insert` BEFORE INSERT ON `books`
FOR EACH ROW BEGIN INSERT INTO content SET service=1; SET NEW.content_id = LAST_INSERT_ID(); END
//

Ну и для удаления:
DROP TRIGGER IF EXISTS `t_books_delete`//
CREATE TRIGGER `t_books_delete` BEFORE DELETE ON `books`
FOR EACH ROW DELETE FROM content WHERE id=OLD.content_id
//

Как это работает:


Добавляем строку в таблице books, а работаем с таблицей content: в зависимости от типа сервиса мы выполняем JOIN к нужной таблице (в данном случае books):
SELECT * FROM content AS c
JOIN books AS b ON b.cid=c.id WHERE c.id={$cid}

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

Так же создаем таблицу films, с двумя триггерами. И наслаждаемся тем, что все реализованные функции уже доступны для фильма как «контента».

PHP:


Content:
class Content{
public $sTableName = '';

public void getInfo($cid){
return $dbsl->fetchAll("SELECT * FROM content AS c, {$this->sTableName} AS t WHERE t.cid=c.id AND c.id={$cid}");
}

public vote($cid, $uid, $rating){
return $db->Query("SELECT vote({$cid}, {$uid}, {$rating});");
}
}

Books:
class Books{
public $sTableName = 'books';
}

Films:
class Films {
public $sTableName = 'films';
}

Заключение:


Я нахожу многовероятным, что кому-то такой подход покажеться не лучшим или вообще плохим, однако же хочу заверить, что при большом числе операций над «контентом» и разнообразием контентов в 4 вида такой подход оправдывает себя. в частности на создание движка и одного типа контента ушло примерно месяц, на добавление каждого последующего типа уходило 2-4 дня. Могу уверенно сказать, что такой подход себя оправдал.

P.S.:


Ну а если есть необходимость и возможность — используйте СУБД которые подерживают наследование, и всем будет легче :)

Что бывает, если MTU выше нормы

Написать о не очевидной сетевой проблеме, проявляющейся по-разному, но имеющей один корень, меня побудил один интересный случай.
Совсем недавно одному удаленному бухгалтеру понадобилось подключаться по RDP к нашему терминальному серверу для работы с 1C. Виндовый админ выделил нужные права, завел учетку, с моей стороны тоже проблем нет: IP клиента статический, а RDP использует TCP порт 3389, который сразу и был проброшен на терминальный сервер:

iptables -t nat -A PREROUTING -p tcp -s $ext_term_access -d $INET_IP --dport 3389 -j DNAT --to-destination $SRV1C
iptables -A FORWARD -p TCP -s $ext_term_access --dport 3389 -d $SRV1C -j ACCEPT


Проверили конфигурацию с внешнего компьютера, успешно соединились, клиенту сразу был дан ответ «Готово, подключайтесь». Ко всеобщему удивлению клиент не смог соединиться, с его стороны соединение «зависало», не выдавая ошибок. Мы проверили конфигурацию с еще нескольких внешних компьютеров, и везде соединение шло гладко. Пришлось списаться с их сисадмином, который, вместо того, чтобы подумать вместе, заявил, что проблема явно у нас, и что его клиенты подключаются таким образом ко многим серверам, а его ISA (это, вроде, такой виндовый фаерволл) и вовсе безупречна. Несколько дней я ломал голову над этой проблемой, даже временно частично или полностью отключал фаерволл, после чего выяснилось, что консольный-то доступ к терминалу у клиента работает. Подозрение сразу пало на некорректный MTU, так как присутствовал самый явный симптом: текстовая информация и прочая мелочь размером до полутора килобайт передавалась успешно, а с более весомой графикой возникали проблемы.
Читать дальше →

Какой шаблонизатор выбрать? Написать свой!

Добрый вечер.

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

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

Ещё один способ интеграции Сodeigniter и Doctrine

Здравствуй уважаемый %username%!


На тему интеграции данного фреймворка уже написана не одна статья, есть информация в вики (раз и два), но всё-таки я решился написать этот текст потому что все представленные выше способы не отличались элегантностью
Читать дальше →

Альтенативный взгляд на популярные модели работы веб-приложений на РНР. Собственные предложения по оптимизации.

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

Предисловие



В наше время что главное для любого приложения, а особенно веб? Устойчивость, маштабируемость, быстродействие. И разработчики в меру своих сил и возможностей стараются воплотить в жизнь свои представления о идеальном приложении. Все началось с того, что у меня возникла очередная идея безусловно полезного и относительно незаменимого приложения на РНР. Приступая к его реализации я стал думать о том, чтобы построить данное приложение на базе фреймворка, коих в сети навалом. Проанализировав наиболее популярные фреймворки я пришел к выводу, что 95% данного «софта» представляют собой заготовку CMS без предустановленного дизайна. По крайней мере мне так показалось.
Но это было не то, что я хотел увидеть в качестве фреймоврка. К слову сказать, пользовательская сторона проекта была сведена к минимуму, основной упор делался на серверные операции. Мне не нужен был функционал, который могла мне дать обычная CMS-ка. Мне нужна была «библиотека отлаженного кода» который я могу бы, покурив мануала, спокойно использовать вперемешку с собственным кодом.
Результатом размышлений по данному поводу есть этот топик.

Основная идея



Библиотека классов с двумя режимами использования.
  1. В качестве встраиваемых, независимых друг от друга библиотек методов, с набором необходимых свойств;
  2. Как целостная вычислительная система, которая адаптируется под нужды пользователя.


Реализация



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

Итак ядро. Оно представляет собой набор классов, в которых прописана базовая функциональность: работа с ФС, базами данных, сессиями, графикой, логирование, и буферизация. Его составные части — классы, которые написаны таким образом, что могут функционировать независимо друг от друга. Вы спросите: «А как же общая конфигурация?». Решение данной проблемы — так называемый клас concentrator.
Немного о нем. Вот думаю большинство из тех, кто сейчас читает этот топик знает принцип работы ядра Linux. При запуске системы в первую очередь запускается процесс init, который потом, с помощью форкинга дает начало всем остальным процессам. То бишь все процессы пользователя являются дочерними по отношению к init. Этот же принцип положен в основу работы класса concentrator. «Внешне» все классы ядра, по сути, ничего не объединяет. Это позволяет встраивать их в любое месть любого кода, независимо друг от друга. А если разработчик захочет собрать их воедино, то сможет сделать это с помощью класса concentrator. Он выполняет функции «колпака», под которым могут взаимодействовать все необходимые разработчику классы и отдельные методы. Класс имеет собственное API, что позволяет сторонним разработчикам дописывать или редактировать уже существующее классы под собственные нужды.
В самом начале я говорил о большом количестве «ненужного» кода, который не работает. Так вот, клас concentrator подключает не все подряд методы, из вызванных классов. При первом запуске собранной из «кирпичиков» системы, создаются дочерние классы, которые наследую только те функции родительских, которые действительно нужны для работы. При необходимости расширения функционала, подобную процедуру можно будет вызвать повторно.

Система дополнительных модулей чем-то схожа, опять же, с ОС Linux. Когда разработчик захочет доустановить модуль, то тот (модуль) будет работать на основе тех методов, что уже прописаны в классах ядра. То есть используется система зависимостей. Линуксоиды меня поймут. Если хочешь установить модуль, установи вместе с ним библиотеку для ядра, которая будет реализовывать методы, необходимые для функционирования модуля. А если у тебя уже есть данный модуль, то все отлично. Таким образом достигается «уникальность» кода внутри системы, не будет функций в разных модулях, которые будут выполнять одни и те же операции.
Опять же, все дополнительные модули работают под колпаком класа concentrator.

Выводы



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

Разворачивание WinXP через службу WDS в Windows Server 2008R2

Задача
Развернуть windows xp через Server 2008 WDS

Предположения
у нас есть домен AD, в нем настроен DHCP и на том же сервер стоит WDS server

Необходимое ПО
1) Необходим пакет Microsoft WAIK
2) Пакет deploy.cab (есть на диске дистрибутива, в папке Support/tools
3) и желательно OPK tools (там хелп по winbom.ini)

Действия

1) Подготовка загрузочного образа WinPE
— ставим WAIK
— в пакете есть образ — по дефолтуC:\Program Files\Windows AIK\Tools\PETools\x86\winpe.wim,
копируем его в %root_wds%\boot, где %root_wds% — корневая директория WDS
— запускаем от администратора утилиты пакеты WAIK (cmd-консоль)
— в консоли говорим
imagex /apply %root_wds%\boot\WinPE.wim 1 %temp%\WinPE (распаковываем образ)
— копируем все необходимые приложения (imagex,bootsect, и т.д.) к примеру в %temp%\WinPE\Windows
— правим файл %temp%\winpe\windows\system32\startnet.cmd, дописываем в него
wpeutil createpagefile /path=c:\pagefile.sys (использовать файл подкачки)
wpeutil initializenetwork (инициализировать сеть)
net use z: \\path_to_share_image (монтируем сетевой диск)

Все танцы вокруг startnet.cmd сделаны для того, что бы можно было ограничится 256 метрами оперативы на станции
Как видно мы используем файл подкачки на диске С и понятно, что если файловой системы на диске С нет или есть какие проблемы с диском, то мы получим ошибку.Если файл подкачки не использовать, то winpe загрузится, но сети не будет!

peimg /prep %temp%/Windows (удаляем все не нужное; в исходном образе есть разные пакеты, но они не установлены)
imagex /boot /compress max /capture %temp%\WinPE %root_wds%\boot\winpe_min.wim "WinPE min"

Таким образом мы создали образ WinPE c минимальным наборов утилит, необходимых для заливки станции.
Дальше добавляем образ в загрузочный на сервере, через консоль WDS

2) Подготовка станции эталона
— обычным образом устанавливаем и настраиваем WinXP (профиль Администратора после sysprep переносится как default)
— дальше создаем на диске папку c:\sysprep и распаковываем туда содержимое архива deploy.cab
— запускаем setupmgr, говорим, что нам нужен sysprep.inf и полностью автоматическая установка.
— выбираем все нужные параметры, файл сохраняется там же, под иненем sysprep.inf
— добавляем в sysprep.inf
[Sysprep]
BuildMassStorageSection = Yes
[SysprepMassStorage]

— дальше запускаем sysprep –bmsd.
Это изменит sysprep.inf и добавит все известные установке Windows идентификаторы запоминающих устройств
— после окончания говорим sysprep -factory -activated
— станция перезагрузится и мы получим машину в factore mode.
В этом режиме все еще можно устанавливать ПО и модифицировать систему.

3) На всякий случай можно сделать образ системы в factory mode
— загружаем станцию по сети с WinPE
— в консоли
imagex /capture c: z:\path_to_image "Windows XP Factory Mode"

4) После этого, загружаем станцию в factory mode
— создаем файл winbom.ini в директории c:\sysrep\
— в него пишем
[factory]
Reseal = yes
ResealFlags = -activated
ResealMode = Mini

— отправляем станцию в перезагрузку
— после перезагрузки заходим. автоматом выполнится sysprep и станция выключится

5) Создаем образ для разворачивания на конечных компах
— загружаем WinPE
— пишем
imagex /append z:\path_to_image "Windows XP deploy image"
— все образ для развертывания готов

6) Разворачивание образов
— Для самого развертывания можно либо создать еще один образ и модифицировать его startnet.cmd, либо в существующем убрать
wpeutil createpagefile /path=c:\pagefile.sys
wpeutil initializenetwork
net use z: \\path_to_share_image

— так как диск может быть и не расформатированным подходящим способом, пишем коммандый файл типа такого
echo WARNING!All data on disk erase
diskpart -s disk_c.txt
bootsect /nt52 c:
wpeutil createpagefile /path=c:\pagefile.sys
wpeutil initializenetwork
net use z: \\path_to_share /user:xxxx\srv-im_winxp PassW0Rd
imagex /apply z:\winxpsp2ru\deploy_v2.wim 1 c:\

Вот файл disk_c.txt
select disk 0
clean
create part primary size=3096
active
select part 1
assign letter=c
format fs=ntfs label="sys"

Теперь достаточно загрузится и сказать install_xp.cmd
После того, как все отработает и загрузится компьютер готов!

PS
Можно добавить образ в WDS Install Images и дальше работать уже средствами WDS и загрузчика Windows 7
Плюсы
1) Более безопасно
2) Мультикаст
Но здесь ограничение
1) сначала нужно модифицировать загрузочный сектор, но возможно это можно сделать запихнув вызов bootsect в startnet.cmd
1) 256 мб мало, минимум 512
2) Нужно больше места, так как образ сначала копируется, а потом распаковывается

PSS
Несколько советов по работе с образами wim
1) Образы содержат файловый снимок — это снимает ограничения на дисковые конфигурации (т.е на эталоне размер диска не равен размеру диска на конечном компе)
2) Образы хорошо сжимаются
3) Есть полезная опция /append позволяющая дополнять образы, т.е
если нам нужно монтировать и изменить образ factory то мы пишем
imagex /mountrw path_to_image 1(номер образа) path_extract
если deploy
imagex /mountrw path_to_image 2(номер образа) path_extract
4) Чтобы сохранить изменения достаточно сказать
imagex /unmount /commit
5) Можно указать свои список файлов исключения для копирования или сжатия
6) Образы на сервер добавляется через консоль WDS, после правки образа нужно говорить Replace и указывать путь к образу
7) Ну и что бы быть честным ссылки
12 ...
601