
Калашников.ru - Ассемблер? Это просто!.. (Выпуск № 014)
InterReklama Advertising
Доброе время суток, друзья мои!
Выпуск N 014
Какой чудесный день!
Какой крутой мой "Пень"!
Какой веселый я:
Рассылочка пришла!
Чего у нас сегодня-то?
Заметки, вопросы, новости
Создается клуб экспертов !!!
Ваши письма
Оболочка Super Shell!
Заметки, вопросы, новости
Ох, друзья мои! Ну и болел же я! Целую неделю. К сожалению, так и не смог выпустить этот номер рассылки вовремя. В связи с этим прошу прощения за такую длинную задержку. Хотелось бы и вас предупредить: будьте осторожны! Не болейте!
Дорогие мои подписчики! Я печатаю рассылку для того, чтобы вы научились писать программы на Ассемблере. Более того, я очень хочу привить у вас любовь к самому языку и показать то, что он не такой уж сложный. Я очень рад тому, что многие используют информацию с рассылки для написания контрольных и/или лабораторных работ. Я просто счастлив, что смог кому-то помочь!
Однако, я был бы очень разочарован, узнав, что информация из рассылки "Ассемблер? Это просто! Учимся программировать" используется кем-то в коммерческих целях. Прошу вас: уважайте, пожалуйста, чужой труд! Если у вас есть предложение по использованию информации в рассылке не только для собственного, частного использования, но и в коммерческих целях (сюда НЕ входит написание собственных рефератов, контрольных и лабораторных работ и т.п.), то, будьте так добры: напишите мне ваше предложение! Мы найдем общий язык!
В противном случае, мне придется поступать по всей строгости Закона РФ "Об авторских и смежных правах".
____________________
Ко мне пришло много писем с просьбой включить e-mail в базу данных с тем, чтобы автоматически высылать вам файлы-приложения к рассылке (sshell.asm, virus.asm, resid.asm). Я отправляю их порциями по 10-20 адресам. Верю, что все подписчики порядочные и солидные люди. Однако, если кто-либо получит некоторое подобие спама, используя адреса, перечисленные в поле "Кому:", сообщите мне об этом. Будем таких искать и безбожно бить ногами...
___________________
Почему мы пишем только *.com файлы? Да потому, что модель памяти в Windows очень напоминает модель памяти *.com-файлов, которые мы сейчас рассматриваем. Конечно, мы напишем несколько примеров *.exe-файлов, но это будет попозже.
К слову. Модель памяти в *.com-файлах называется TINY (крошечная). В Windows - FLAT (плоская или как это?).
____________________
Хочу спросить у образованных людей: есть ли в русском языке слово "запомненный"? Если нет, то каким словом его можно заменить?
Пример: "Достаем со стека запомненный адрес строки".
Спасибо!
____________________
Совсем недавно я поместил на сайт свой небольшой фотоальбом, в котором можно посмотреть фотографии моей жены, сына, брата, сестры, отца, матери, а также меня лично. Если Вам интересно, то можете заглянуть в свободное время...
Создается клуб экспертов
Итак, время пришло! Некоторые уже ознакомились с условиями на сайте, но я все же рекомендую прочитать то, что находится в данном разделе рассылки, причем всем подписчикам.
Не все имеют прямой и постоянный выход в Сеть. В связи с этим я постараюсь вкратце объяснить суть нашего так сказать эксперимента.
Почему я решил сделать это?
Ко мне приходит много писем с различными вопросами (как по Ассемблеру, так и по другим темам; например, по работе с DOS). Я, как уже писал, не успеваю отвечать на все ваши письма. Поэтому я решил провести небольшой эксперимент: создать т.н. "Клуб экспертов".
Что из себя представляет этот (как его?) "Клуб экспертов"?
В него может войти любой человек, который решит принять на себя ответственное и непростое задание и попробоваться в роли "учителя", стать т.н. экспертом. Или, проще говоря, отвечать компетентно на вопросы подписчиков. Например:
Вася не умеет работать с DOS (не знает, как запустить программу, распаковать файл, как пользоваться MASM / TASM и пр.);
У Пети возник вопрос по поводу работы дизассемблера;
Саша написал свою программу, используя знания полученные из рассылки, но - вот беда! - она не работает так, как Саша хотел бы. Что делать?
Вова вообще только что подписался и не знает что да как. Куда и к кому обратиться?
Дима не понял ничего в стеке. У него возник вопрос. Кто сможет помочь нашему подписчику?
и пр.
Зато у Сергея есть время, определенные знания и желание отвечать на вопросы, помогать другим освоить Ассемблер, но нет возможности. Более того, Сергей знает, что при объяснении темы или при ответе на вопрос сам чего-то да начинает понимать. Т.е. будет учиться сам, обучая других.
Я хочу предоставить эту возможность Сергею и всем остальным, кто имеет то же желание.
Каков принцип работы клуба?
Например, у меня зарегистрировалось 5 специалистов-экспертов, которые изъявили желание отвечать на вопросы связанные с DOS. Вася (который не может разобраться с DOS) высылает мне письмо с вопросом, которое автоматически направляется всем пятерым экспертам. Эксперты, в свою очередь, отвечают на вопрос и отправляют его напрямую Васе. Т.о. Вася получит 5 писем с ответами на свой вопрос. Из одного письма он почерпнет одно, из другого - второе и т.д. При этом эксперт направляет мне копию данного письма. Нет, не для того, чтобы я проверял, а для того, чтобы я мог создавать потихоньку базу данных вопросов/ответов, которую потом выложу на сайт. При этом, естественно, письмо будет сохранено в первозданном виде, причем имя и e-mail эксперта остается (если он этого захочет).
Что я могу предложить экспертам?
Вася, получивший 5 писем с ответами направляет мне оценки всем пяти экспертам по пятибалльной шкале (неужели Васе будет это сложно сделать?). Т.е. Валик ответил на "отлично", а Толик на "троечку" еле тянет. Я периодически опубликовываю в рассылке имена экспертов и количество набранных ими баллов.
Тройка лидеров получает возможность:
опубликовать в рассылке любую информацию о себе;
указать в рассылке адрес своего сайта;
разместить какую-нибудь рекламу;
Эксперт, занявший первое место, может получить, помимо вышеперечисленного, еще и денежку за труды. Много не обещаю, т.к. собираюсь платить со своего кармана, но на пивко хватит.
Почему я написал "может"? Потому что какое-то время (пока система не заработает в определенном ритме, если она вообще заработает!) денежки выплачиваться не будут. Зато потом можно будет заработать не только на пивко, но еще и на воблочку. А там, глядишь, и до икорки дойдет... По крайней мере, я очень на это надеюсь...
Но не все так просто. Все эксперты должны соблюдать определенные правила, которые будут высланы им в скором времени. Количество экспертов ограничивается пока 10 человеками на одну тему.
Что требуется от подписчиков, задающих вопросы?
Прежде всего - порядочность и внимательность. А именно:
обязательно отправлять мне справедливо поставленную оценку за ответ (если Вам помог эксперт в том или ином вопросе, навел Вас на Мысль, то почему бы Вам не помочь ему и наоборот?). Момент! Эксперты не будут знать какую оценку дал подписчик на его ответ!;
четко излагать вопрос, передавая эксперту как можно больше информации ("У меня не работает компьютер. Что делать?" - не годится! В лучшем случае эксперт ответит Вам: "Попробуйте воткнуть вилку в розетку!", на что Вы посчитаете его идиотом и отправите мне оценку за ответ "кол". А это несправедливо!);
не задавать вопросы, например, эксперту по оболочкам DOS, касающиеся, скажем, работы с отладчиком (эксперт, которому пришел вопрос "не по адресу", на него не отвечает!);
обязательно указывать в теле письма свой адрес (а иначе как ответит Вам эксперт? Письмо-то я фактически буду отправлять!);
не использовать в корыстных или иных подобных целях адреса экспертов (найду - не знаю, что сделаю!);
отправлять мне письмо, если никакого ответа не последует от экспертов вообще (что я сомневаюсь, но все-таки!);
в любых спорных случаях присылать мне письмо (жалобу), цитируя при этом переписку с экспертом.
Все вышеперечисленное - самое главное! Для этого я и хочу сперва пропускать письма через свой ящик.
_______
Ниже приведена перечень тем для вопросов, который будет теперь присутствовать во всех выпусках (может, чего-нибудь другое придумаю, чтобы не нагружать выпуски). С левой стороны указана экспертная группа, а справа, в скобках типичный вопрос к данным экспертам, после этого указан адрес с меткой в поле "Тема", откуда нужно будет отправлять вопрос:
виды и типы компьютеров ("У меня 486. Это нормально и чем он отличается от Pentium?"), assembler@beep.ru?Subject=QuestionExpertComputers;
команды DOS (что такое файл, как копировать файлы, как запускать программы и т.п.), assembler@beep.ru?Subject=QuestionExpertDOS;
оболочки под DOS (Norton Commander, DOS Navigator, Volcov Commander и т.п.), assembler@beep.ru?Subject=QuestionExpertDOSShells;
основы работы с Windows'95/98/2000 / NT ("Почему не запускается MASM под Win NT?"), assembler@beep.ru?Subject=QuestionExpertWin;
работа с ассемблерами (MASM/TASM; как сассемблировать программу, что означают другие параметры в командной строке), assembler@beep.ru?Subject=QuestionExpertAssemblers;
работа с отладчиком AFD, assembler@beep.ru?Subject=QuestionExpertAFD;
работа с отладчиком CodeView, assembler@beep.ru?Subject=QuestionExpertCV;
работа с отладчиком TurboDebugger, assembler@beep.ru?Subject=QuestionExpertTD;
работа с дизассемблерами (как и что), assembler@beep.ru?Subject=QuestionExpertDisassm;
Ассемблер: общие вопросы, не рассматриваемые в рассылке ("Посмотрите мою программу и исправьте ошибки"), assembler@beep.ru?Subject=QuestionExpertgeneralassm.
Пожалуйста, проверяйте, чтобы в поле "Тема" Вашего вопроса была соответствующая строка, которая идет после "?Subject=" !!!
Вопросы, которые вы присылали мне и не получили ответ, пожалуйста, перешлите соответствующим экспертам. Спасибо.
Оболочка Super Shell!
Сегодня у нас довольно-таки нудный и неинтересный выпуск. Но то, что мы будем рассматривать в нем, очень важно! Вам придется вспомнить основы математики и немного "пошевелить мозгами". Да-да, друзья мои! А как вы хотели выучить Ассемблер без элементарных знаний математики? Я подчеркиваю: элементарных. Вам придется хорошо поработать сегодня! Хотя, большую часть работы я для вас сделал, а именно: продумал алгоритм вывода на экран любого окна (или рамки) в центр экрана. Вам осталось только внимательно с ним ознакомиться и разобраться.
Полная просьба: внимательно ознакомьтесь с данным выпуском и прилагаемым к нему файлом Sshell14.rar!
Файл-приложение можно взять здесь: http://www.Kalashnikoff.ru/Assembler/Programs/Lessons/Sshell14.rar
Если у вас нет выхода в Сеть, то напишите мне письмо с просьбой выслать. Я также включу ваш адрес в базу данных. Затем, перед выходом очередной рассылки, вы получите этот файл по почте.
Давайте договоримся о некоторых определениях. Т.к. программа у нас будет большая, то для облегчения читаемости и поиска необходимой процедуры, я буду указывать в скобках процедуру и файл, где нужно искать то, о чем я напишу в рассылке. Например,
"...Затем мы удаляем файл (Delete_file, FILES.ASM)..."
Здесь: Delete_file - процедура, которая удаляет файл, а FILES.ASM - файл, где нужно ее искать.
Ну, понеслась...
Сразу заглядываем в файл MAIN.ASM. Перво-наперво, что нам нужно сделать, так это спрятать курсор (Hide_cursor, DISPLAY.ASM). Прежде, чем это сделать, нужно запомнить его текущую позицию. Это позволяет сделать функция 3 прерывания 10h:
Вход: AH=3BH=видеостраница, с которой получить текущую позицию курсора
Выход: DX = текущая позиция курсора (DH - строка, DL - колонка) Как видите, BH должен указывать на видеостраницу, с которой нужно сосчитать позицию курсора. Как уже вам известно, видеокарта имеет достаточно памяти для размещения 8 видеостраниц. Каждая видеостраница имеет свой курсор. Но мы-то будем отображать все на нулевой странице, следовательно, мы должны в BH загрузить 0. На выходе DX будет содержать текущую позицию курсора: DH - строку, а DL - колонку. Причем, отсчет идет с нуля.
После того, как мы получили текущую позицию курсора, можно его прятать. Самый распространенный метод - установка курсора за границу экрана. В нашем случае - установка на 25 строку. Режим-то у нас будет 3 (25 строк, 80 колонок). Т.к. отсчет идет с нуля, то последняя позиция курсора (самая нижняя строка) - 24. Следовательно, установив курсор на 25 строку (19h), мы его просто "прячем"!
Установить курсор на нужную позицию на экране позволяет сделать функция 2 прерывания 10h:
Вход: AH=2BH - видеостраница, на которой будем устанавливать курсор
DH - строка, DL - столбец для установки
Выход: Ничего После того, как мы спрятали курсор, можем переходить к сохранению текущего содержания видеостраницы 0. Как вы знаете, все уважающие себя оболочки сохраняют и, при необходимости, показывают пользователю то, что изображено на экране. Например, Norton Commander или DOS-Navigator, которые отображают пользовательский экран при нажатии на клавиши <Ctrl+O>.
Как ее сохранить? Помните, я говорил о том, что у видеокарты есть достаточно памяти для размещения 8 видеостраниц? Почему бы нам не скопировать содержимое пользовательской, нулевой страницы в первую? А что тут такого?
Вот мы это и делаем (Save_mainscr, DISPLAY.ASM). Здесь мы встречаем новые операторы: PUSHA и POPA (POPA значит POP All - вытолкнуть все (а не то самое...), а PUSHA - PUSH All - втолкнуть все). Т.е. этот оператор толкает в стек регистры в следующем порядке:
AX, CX, DX, BX, SP, BP, SI и DI
и, соответственно, оператор POPA выталкивает их из стека в обратном порядке, т.е.:
DI, SI, BP, SP, BX, DX, CX и AX.
Данные операторы используются только 286+ процессором. Когда пишут, например, что такой-то оператор используется в 386+ процессоре, то это значит, что данный оператор будет работать на процессорах 80386, 80486, Pentium и т.д., но никак не на 8086 (PC/XT) и 80286 (PC/AT).
В нашем случае команды PUSHA и POPA будут работать на 80286 и последующих (более современных) процессорах. Для этого в самом начале файла SSHELL.ASM мы указываем т.н. директиву .286, что говорит ассемблеру (MASM, TASM) о том, что в данной программе могут встречаться команды (инструкции) не только 8086 процессора, но и 80286. "Почему же мы раньше ничего подобного не писали?" - спросит внимательный читатель. "Если ничего подобного не указывать, то ассемблер (MASM, TASM) считает, что в программе используются только инструкции 8086 процессора, что мы до сих пор и делали..." - ответит ваш покорный слуга.
Безусловно, команды PUSHA и POPA удобны в тех случаях, когда нам нужно сохранить в стеке более одного регистра. Они уменьшают размер программы.
Обратите также внимание, как мы заносим в сегментный регистр число:
push 0B800h
pop es
Это получается на 1 байт короче, чем если бы мы делали так:
mov ax,0B800h
mov es,ax
Более того, мы не трогаем регистр AX, что в некоторых случаях бывает полезно.
Команда вида
PUSH 1234h
работает также на процессорах 80286+ (если быть точным, то она работает на процессоре 80186+, но т.к. эти процессоры не получили большого распространения в связи с тем, что через несколько месяцев после выпуска 80186 появились 80286, то о них (о 80186) вообще мало кто знает).
Все остальное в данной процедуре (Save_mainscr, DISPLAY.ASM) должно быть понятно... Точно как и в процедуре восстановления экрана (Restore_mainscr, DISPLAY.ASM)...
_______________
Теперь самое нудное (на мой взгляд).
Курсор спрятали, экран пользовательский сохранили. Теперь можно и окно (рамку) рисовать... Будем это делать не прибегая ни к каким прерываниям, т.к. они работают очень медленно. Воспользуемся выводом символов на экран путем прямого отображения в видеобуфер.
С данным методом мы уже сталкивались, когда пытались выводить на экран "рожицу". Теперь рассмотрим его более подробно.
Метод прямого отображения символов в видеобуфер - вывод символов на экран, путем записи их напрямую в сегмент видеобуфера (в память видеокарты), минуя сервис прерываний.
Стоит отметить, что это самый быстрый способ вывода символов на экран. Быстрее уже не существует. Здесь все зависит от профессионализма программиста и - как следствие - алгоритма вывода, скорости его выполнения.
Рассмотрим вкратце модели мониторов, многие из которых уже уши в прошлое, и только старые и добрые игрушки периодически напоминают об их существовании. Вот ряд: MDA (Monochrome Display Adapter), Hercules, CGA (Color Graphic Adapter), EGA (Enchanced Graphic Adapter), VGA (Video Graphic Array), MCGA (Multi-Color Graphic Adapter - подобие VGA), sVGA (Super Video Graphic Array - то, что многие в настоящий момент используют в работе).
Так вот, при попытке вывода символа в мониторе CGA и подобных ему возникает т.н. "снег". Эта ошибка (недоработка?) была исправлена только в EGA. "Снега" не возникало, если символы выводились при помощи прерываний 10h или 21h. Однако, эти прерывания использовали процедуру, которая проверяла состояние луча монитора, в связи с чем скорость вывода символов существенно замедлялась. Не знаю, есть ли в настоящих ПЗУшках и в прерывании 21h подобная процедура или нет. Главное - при выводе символов через прерывания скорость резко снижается. Полагая, что никто из вас не использует сейчас CGA монитор, будем выводить символы прямым отображением в видеобуфер. Повторю еще раз: это очень быстро даже на 8086 процессорах. Очистка экрана в PC/XT происходит мгновенно. И уж тем более на 80286+...
Для процедуры (а может и не только для нее) заведем две переменные: Height_X и Width_Y. Пока временно. В дальнейшем научимся передавать данные в стеке. Но это будет позже, а сейчас переменная Height_X содержит высоту рамки, а Width_Y - ширину. Num_attr - цвет рамки (Main_proc, MAIN.ASM). Можно вызывать процедуру Draw_frame, которая находится в файле DISPLAY.ASM.
Вот сейчас и рассмотрим самое главное. Итак, процедура Draw_frame.
Перед вызовом данной процедуры необходимо занести некоторые числа в соответствующие переменные (main.asm), а именно:
Height_X - содержит высоту нашей рамки;
Width_Y - содержит ширину нашей рамки;
Num_attr - содержит атрибуты выводимой рамки.
Пока все. Дальше пойдем - больше будет...
Итак, занесли. Вызываем процедуру Draw_frame (Display.asm).
Теперь внимание! Нужно произвести некоторые расчеты перед тем, как вывести рамку не "абы куда", а именно в самый центр экрана.
Нам нужно разделить высоту рамки на 2 и вычесть из полученного числа середину высоты. Вот так:
(1) mov ax,Height_X
(2) shr al,1
(3) mov dh,11
(4) sub dh,al
В строке (1) заносим в AX высоту рамки, которую указали перед вызовом процедуры. Затем, в строке (2), оператор SHR сдвигает все биты в регистре AL на 1 вправо. Что получается? Вот пример:
mov ax,16 --- AX = 10000b, т.е. 16
shr ax,1 --- AX = 1000b, т.е. 8
shr ax,1 --- AX = 100b, т.е. 4
shr ax,1 --- AX = 10b, т.е. 2
shr ax,1 --- AX = 1b, т.е. 1
Т.о. сдвиг битов вправо на единицу делит число на 2. На двойку - в четыре раза и т.д. Это быстрее, если бы мы пользовались оператором DIV (который, кстати, мы еще не изучили) - деление.
В строке (3) мы заносим в DH середину (или почти середину) экрана (по горизонтали), т.е. 11. И вычитаем из 11 полученный результат.
Например, мы выводим рамку высотой в 5 строк. Вот, что получим:
AX=10
AX=AX/2=5
AX=11-5=6
Т.о. вывод начнем со строки 6.
Все тоже самое мы делаем с колонками (вертикально). Посмотрите в прилагаемом примере...
В принципе, пока особо не заостряйте внимание на этом: со временем придет опыт и более точное понимание.
Как только мы вычислили координаты для вывода рамки в центре экрана, мы переводим высоту/ширину в линейный адрес. Что такое линейный адрес и зачем нужно переводить в него?
Как вы уже знаете, то, что находится на экране, расположено по адресу от 0B800:0000 до 0B800:1000h (если нулевая страница). Видеокарта не знает, что такое колонка и строка. Для нее все данные расположены в линейном массиве, т.е. от 0 до 1000h. Т.к. один символ занимает 2 байта (символ и атрибут), то одна строка 3 режима занимает 160 байт (80 строк * 2 = 160). Для того, чтобы вывести символ в первую строку (т.е. во вторую, т.к. отсчет с нуля), нам нужно выводить его по адресу 161, смещения 0B800h. Следовательно, если мы указываем строку/столбец, то нам необходимо перевести эти числа в линейный массив, "понятный" видеокарте. Вот пример (разбираем внимательно!):
mov dh,0 ;DH обычно указывает на строку
mov dl,15 ;а DL - на столбец (это мы и будем делать во всех наших процедурах)
;т.о. мы выводить будем в нулевой строке (т.е. самой верхней на экране), 15 столбце.
Вот переводим два числа в линейный массив (переведем в одно число - смещение):
Linear = DL*2
Умножаем на два строку, т.к. один символ на экране занимает два байта: символ+его атрибут
Linear = Linear + DH*160
Теперь переменная Linear равна 30. Вот он, линейный адрес: 0B800:001Eh (1Eh = 30)!
Еще пример:
mov dh,8 ;строка 8
mov dl,56 ;столбец 56
Linear = DL*2
теперь Linear = 112
Linear = Linear + DH*160
Теперь Linear = 1392 или 570h
И последний пример. Произведем вычисления для последнего символа на экране (нижний правый угол):
Linear = (24 * 160 + 80 * 2) - 2 = 0F9Eh
80 - количество столбцов на экране, которое нужно умножить на 2 (учитывая не только символ, но и его атрибут).
24 - количество строк на экране, начиная от 0. Т.к. в одной строке 80 символов (начиная от 1) * 2 = 160, то, для того, чтобы получить адрес самого последнего (24-ого) ряда, нужно 24*160.
Затем все это дело сложить (адрес 24-ой строки плюс адрес последнего символа минус два). Еще раз:
(24-ая строка * 160 + 80-ый символ * 2) - 2
или
(24 * 160 + 80 * 2) - 2 = 3998 или 0F9Eh
Почему "минус два"? Потому, что... А, хотя, подумайте сами... Я и так тут порасписывал...
Я лучше расскажу, как это выглядит на практике. Итак, процедура (Get_linear, DISPLAY.ASM) (хотя, многое и так понятно из описаний в файле):
shl dl,1 ;умножаем DL на 2 (DL=DL*2)...
Просто сдвинем биты на 1 влево (по принципу деления. См. выше).
mov al,dh ;в AL - ряд,
mov bl,160 ;который нужно умножить на 160
mul bl ;умножаем: AL (ряд) * 160; результат в AX
Что-что? Новый оператор MUL? Ну так рассмотрим сейчас.
mov di,ax ;результат умножения в DI
xor dh,dh ;аннулируем DH
add di,dx ;теперь в DI линейный адрес в видеобуфере...
Итак, вот таблицы с новыми операторами:
Название Перевод Применение Процессор shl источник, приемник SHift Left - сдвиг влево Сдвиг байт 8086 Пример:
mov ax,100b
shl ax,1 ; Теперь в AX число 1000b
--------
Название Перевод Применение Процессор shr источник, приемник SHift Right - сдвиг вправо Сдвиг байт 8086 Пример:
mov ax,100b
shr ax,1 ; Теперь в AX число 10b
--------
Название Перевод Применение Процессор mul bl Multiplex - умножение Умножение 8086 Умножает AL на BL, помещая результат в AX. Пример:
mov al,5
mov bl,2
mul bl ; Теперь в AX число 10
Ну вот, собственно, и все. Остальное должно быть понятно из комментариев к программе.
Если у Вас есть вопросы, то задавайте их, пожалуйста, экспертам (в редких случаях можно и мне).
Удачного Вам программирования!
С уважением,
Автор рассылки:
Калашников Олег
www.Kalashnikoff.ru
E-mail:
assembler@beep.ru
UIN (Тетя Ася):
68951340
(С) Авторское право. Запрещается использование материала из рассылки в коммерческих целях без письменного согласия автора. [Следующий выпуск] [На главную страницу]
u="u496.71.spylog.com";d=document;nv=navigator;na=nv.appName;p=1; bv=Math.round(parseFloat(nv.appVersion)*100); n=(na.substring(0,2)=="Mi")?0:1;rn=Math.random();z="p="+p+"&rn="+rn;y=""; y+=""; y+=""; y+=""; d.write(y);if(!n) { d.write("