Flash ActionScript и странные аттракторы
Я уже как-то рассказывал и показывал, как работает сервер приложений Cold Fusion от Macromedia. Но вот, опять встречаю человека, а он мне и говорит: "А-а-а, флэшки? Это которые картиночки про Масяньку?". Елы-палы, объясняю для детей природы…
Вот уж люди: любят носиться со своими предрассудками — и что обидно, еще и живут при этом долго. Ну какая же там за бесценок продавшаяся Масянька, если "флэш анимейшин" — это на сегодня самый простой и очень мощный способ кросс-платформенного самовыражения.
Конечно, происхождение флэшки — самое что ни на есть простецкое, первые версии вообще не далеко ушли от анимированных GIF’ов, но главное, как поняли макромедийцы,— это попасть на комп пользователя и подсадить народ на продукт, чтобы люди апгрейдились и апгрейдились. Сам апгрейд через плуг — это пожизненный памятник Flash’евским создателям.
Вот так вот под шумок у нас на компьютерах и поселилась самая что ни на есть операционная среда Flash и виртуальная Flash-машина.
Изначально Flash работал только под MS Windows и Mac OS. Благодаря фирме Sun Flash был портирован под X-Windows, то есть на Solaris, IRIX, BSD, Linux. Количество установленных Flash-плееров приблизительно равно количеству установленных браузеров, которые, в свою очередь, в любом случае сопутствуют графическим оболочкам, таким как KDE. Короче, на сегодня вероятность встретить на персональном компьютере Flash-плеер составляет около 86%, и то последние 14% относятся к "только что установленным", на которые плагин просто не успел попасть.
Конечно же, первую роль играет красивая анимация — но, заметьте, сетевая анимация. То есть поддерживается доступ к сетевым ресурсам для загрузки данных и изображений. Конечно, все это ограничено довольно специфичными рамками, но главное — есть доступ к серверам приложений. А значит, все, что нельзя сделать, локально можно делегировать серверу. И в этом заключается прикол, так и должны работать сетевые приложения.
Важен и фактор компактности самого плеера, который на сегодня не превышает 400 Кб для большинства платформ. Такой плеер легко встроить в любой смартфон или хэндхэлд. Сравните с виртуальной машиной Java даже в минимальной версии. Конечно же, на стороне Java — мощность и богатство платформы, но у этой мощности имеются не только стороники, но и противники. Есть же люди, платящие суммы как за супермощные джипы, так и за маломощные и экологичные автомобильчики — и последних все больше. Так и в программировании: для изучения всех иерархий классов и разработки новых иерархий в Java может понадобиться много месяцев. А задача за это время может быть решена на Flash — и при том, заметьте, серверная часть будет портабельной и инвариантной, так что тут даже больше гибкости и правильности. О том, что фронт-энд будет красивее на Flash, можно и не говорить — конечно, если под рукой есть про-дизайнер с руками в нужном месте.
Ладно, хватит чесать блох — переходим к практике дзен. Практику нам раздали такую: создать портабельное, интерактивное, распределенное приложение. Причем никаких масянек, никаких летающих пингвинов — что-то из мира науки, что-то из математики. Что-то, что бы могло показать, что Flash может использоваться в качестве калькулятора.
Задачка: странные аттракторы (очень краткий курс)
Придумал, а точнее — вспомнил. Есть в мире математики такие популярные вещи, как странные аттракторы. Это когда что-то там движется странно. Как известно, когда решаешь дифуру, то в простом случае получается что-то такое периодическое, или не совсем — ну, короче, что-то не странное. Поведение простого колебатора одно из трех: либо затухает, либо выходит на орбиту (тупо аппроксимирует к ней), либо вообще входит в резонанс (само с собой — одна часть уравнения с другой) и разрывает все к ежам, как говорится — "движущиеся части системы выходят из наблюдаемой области". Во втором случае колебатор называют осциллятором.
Ага, нету такого слова колебатор? Ну о’кей, считайте меня автором — с момента публикации у меня на это слово все права.
А потом обнаруживается, что некоторые системы колбасятся по непонятному закону — то есть не видно, где у него период. Одним из простых странных колебаторов является система, описываемая уравнением Дюффинга:
dx/dt=dfy, dy/dt = x-x3 — c*y + A*cos(w*t)
Как видите (ну, типа видите), тут в наличие источник суеты в виде какого-то внешнего колебатора A*cos(w*t) и "гальмо" (энергетическая утечка, в механике — трение) в виде -c*y и, плюс к этому, еще какая-то гадость, описывающая закон движения точки в пространстве в зависимости от времени. Есть несложная физическая интерпретация — но она нам сейчас без интереса. Хотите — почитайте здесь: www.mcasco.com/pattr1.html.
Да, так вот, при некоторых параметрах получаем достаточно замысловатое движение. Странно ведут себя как координата x, так и скорость y. Вот как выглядит, например, жужжание хаотического шмеля.
Координата и скорость точки в хаотическом режиме
Для прикольности можно построить график зависимости x от y — красиво видно, как и куда сходится поведение системы с течением времени.
Скорость как функция координаты
Больше таких картинок вы можете увидеть на сайте, с которого было взято это изображение — линк в конце статьи. Я нарочно взял независимые результаты, чтобы потом сравнить их с собственными, тут никакой ошибки. Интерактивную версию можно посмотреть здесь: http://theory2.phys.cwru.edu/~pete/java_chaos/DuffingApplet.html.
Есть еще вариант: отмечать на графике только точки в одной фазе колебатора возбуждения. Это именно и есть странный аттрактор. Там такой кисель смешной образуется — называется подковообразное преобразование. По этим картинкам определять странность вообще просто. Посмотреть на странный аттрактор "в натуре" в виде gif-анимации можно по адресу: www.sekine-lab.ei.tuat.ac.jp/~kanamaru/Chaos/e/Animation/duffing.html.
Что нас будет интересовать, это то, при каких параметрах проявляется странное поведение. Само поле параметров является слегка глючным: при одних параметрах проявляется странность аттрактора, при других (даже бесконечно близких) — как и не бывало, налицо отвратительная и нежелательная гармония. Вот и постараемся, по крайней мере графически, отобразить области, где странность проявляется, а также области, где таких странностей нет.
Числовые методы в одно касание
Как видим, перед нами дифференциальное уравнение второго порядка. Для этого случая есть старые и миллион раз проверенные числовые методы интегрирования. На самом деле там все проще, чем кажется: вычисления производятся методом "а почему бы и нет" — то есть берется начальная точка и как бы немного аппроксимируется первыми членами разложения Эйлера к следующей в предположении, что это не черт знает где, а где-то рядом. Ну, то есть y[i+1]=y[i]+dy.
Например, большой популярностью у студентов и преподавателей пользуется метод Рунге-Кутты четвертого порядка точности. Не буду вдаваться в подробности — сами посмотрите в тексте программы. Главное, что каждая следующая точка будет вычисляться как функция предыдущей. А поскольку уравнение у нас второго порядка, начальная точка будет задаваться двумя координатами: (x, y), где y — суть функциональная производная от x, но в данном случае мы будет смотреть на нее как на независимую переменную.
Сразу скажу, что мы не будем "бороться" с переменным шагом интегрирования — это, конечно, выгодно с точки зрения вычислений, но усложнит демонстрацию того, что мы тут будем демонстрировать: применение Flash в качестве вычислительной среды.
Немного оптимизации: истребляем в себе все человеческое
Еще чуть-чуть теории — а потом сплошная практика. Поговорим о человеческом факторе в науке.
Если порыться в любой научной отрасли, даже в сравнительно чистой математике или физике, можно найти не только штаны Пифагора, но и старые носки Эйлера. Например, та же десятеричная система появилась благодаря привычке считать на пальцах. Ну разве не абсурдная причина? Та же секунда времени — усредненная частота сердечного ритма. Ну разве не странная единица? Более поздние "находки", типа 360 градусов окружности — это уже дань более ученым расчетам. Не смогли поделить угол на три части, вот и придумали: сделаем в полном развороте 3х4х5х6=360 частей, будет делиться по определению на что угодно.
С другой стороны есть реально интересные числа: то же. Например, стоит договориться с тараканами, что такое окружность, ее центр и радиус, а также выяснить, что такое ряды, так сразу любой таракан сможет доказать вам, что длина окружности, выраженная через ее же радиус, равна Пи.
Короче, старая хитрость: хочешь понять систему — говори на ее языке, а не на своем. Это знают математики и программисты, взять ту же задачу вавилонских башен и ее рекурсивное решение. Оказалось, что есть простое решение, нужно только выбрать точку зрения.
А мы тут при чем? Вот при чем. Как правило, при задании dt в числовых методах используются "отбалденные" значения типа 0,1. Это число просто удобно в десятичной системе счисления — больше в нем ничего хорошего. Даже если применяются методы динамического шага, то в лучшем случае мы перейдем к 0,2 или 0,01. Хрен редьки не слаще.
На самом-то деле наша система обладает своим собственным сердцем: R*cos(wt). Вот это и есть естественный для нашей системы хронометр, часы — или называйте как хотите. Один полный оборот этих часов — это и будет наша единица времени, назовем ее революцией, то есть оборотом.
По ходу задачи для получения аттракторов мы должны будем фиксировать значения в одной фазе нашего колебатора, например в нулевой. Если мы выберем dt произвольно, то не факт, что в одном обороте будет целое число шагов — даже наверняка не будет. В результате наш рабочий цикл для вычисления тысячи точек будет выглядеть примерно так:
int time=0; dt=0.1; cnt=0;
while(cnt<1000) {
x1=fn(x);
if ((2*Pi*(cnt+1))-(tme*w))>=0 {cnt++; … }
x=x1;
}
Короче, мы должны будем отслеживать, как наша "стрелка часов" приближается к нулевой отметке, и брать, например, первую точку, которая прошла "за полночь". Не точно, не удобно и не спортивно. Гораздо проще и куда интереснее разделить нашу революцию на целое число частей (как это сделано с градусами) и "ходить конем" только в эти точки. Тогда вычисления аттрактора будут точными, кратными целому и постоянному числу "ходов".
На сколько частей делить революцию — априори не понятно, но можно предположить, что для вычислений удобными будут степени двойки. Тогда мы сможем для энного хода получать значение mod(n), что для степеней двойки эффективно реализуется отбрасыванием старших разрядов с помощью битовой операции AND.
Введем такую величину, как революция/2n, или сокращенно revN2. Это величина, представляющая деление одного оборота на 2n. То есть: rev8 — 256-я часть от одного оборота, rev10 — 1024-я и т.д. Такая система измерения удобна для компьютера. Например, можно создать объект rev (8, "сos", R, w), который просчитывает косинус с градацией 256 позиций на один оборот, с радиусом R и частотой w и заносит результаты в таблицу-массив. Частота тут, собственно, нужна, для вычисления временного шага: если rev8=2*Pi/2n, то w*dt_revN=2*Pi/2n, в частности w*dt_rev0=2*Pi/20. Это можно реализовать как метод объекта rev, например GetTimeStep().
Теперь все чудно: для получения тысячи точек аттрактора только и нужно, что устроить цикл:
for (i=0;i++;i<1000) for (j=0;j++;j<256)
А значения косинуса можно получать из массива в заранее просчитанном объекте rev:
rev.GetValue(i)
Не буду рассказывать, насколько выборка из массива быстрее вычисления косинуса. Скажу только, что в ActiveScript обе операции реализованы способом, далеким от идеального. Массивы на самом деле представляют собой ассоциативные списки Java, косинус — тоже, очевидно, не реализуется одной процессорной командой, как могло бы быть в идеале. Но и в этом случае массив дает огромное преимущество, включая экономию на одном дополнительном умножении на радиус на каждом расчете. Ситуация осложняется еще и тем, что для расчета одной точки Cos вызывается четыре раза, то есть для тысячи точек и rev8 количество вычисляемых косинусов достигает 4х256х1000=1e6, то есть одного миллиона! Это не шутка даже для ассемблера.
На этом — конец теории, полный и окончательный.
Практика: точки, системы координат, синхронизация etc.
Теперь откроем наш Flash и попробуем что-то там рисовать, в том числе аттракторы. Не будем слишком упираться в красоту, хотя, конечно, не без этого. Для начала: что может рисовать Flash? Ответ: ничего, кроме прямых. Вы в шоке? А как же, по-вашему, должна работать векторная графика? Короче, в нашем распоряжении только два метода: moveTo для перемещения в точку растра объекта MovieClip и lineTo для рисования прямой от текущей точки до другой, которая, соответственно,становится текущей. Кто помнит, все это напоминает первобытные функции рисования в Turbo Pascal или убогую "черепашку" с плоттером в клюве.
Даже рисование точки — уже кое-какая проблема, поскольку если нарисовать прямую из точки до самой себя, то ничего не будет нарисовано. Хотите нарисовать точку — нарисуйте маленький квадратик, или линию, или крестик — так будет лучше всем. Главное — вы можете рисовать отрезок дробной длины, так что крестик 0,1 на 0,1 эффективно закончится пикселем на экране.
Два возможных решения не проходят через цензуру. Первое — рисовать маленький квадратик, закрашенный с помощью BeginFill и EndFill в некоторый цвет, но с прозрачной рамкой. Работает, но по производительности — полный сакс.
Второй метод — клонировать объект типа "точка". Это вообще не работает, потому что на одном фильме может лежать только 255 объектов, каждый на своем слое. Так что много точек таким методом вы не нарисуете. Помещение символа в тот же слой будет удалять предыдущий символ. Если вы помните, как программировались старые игровые приставки, то там тоже в одной строке сканирования не могло разместиться более восьми спрайтов.
Кроме рисования точек нам понадобится преобразование координат из предметной области в условные пиксели рабочей поверхности. Это задача для школьников старших классов, так что не стану на ней останавливаться. Замечу только, что не делаю поверхность рисования динамически растягиваемой, размер подложки постоянный — 1200 х 800. Любое масштабирование объекта MovieClip можно и нужно выполнять (и так оно и будет) средствами Flash, причем с такими чудесами техники, как антиалиасинг. Не будем улучшать совершенное.
Вот как выглядит рисование простейшей системы координат
width=1200; height=800;
dx=20; dy=4;
kx=width/dx; ky=height/dy;
originX=width/20; originY=height/2;
cx=originX/kx; cy=originY/ky;
function x(x1) { return originX+x1*kx; }
function y(y1) { return originY-y1*ky; }
function mv(x1,y1) { moveTo(x(x1),y(y1)) }
function li(x1,y1) { lineTo(x(x1),y(y1)) }
function dt(x1,y1,dcl) {
var xx=x(x1); var yy=y(y1);
lineStyle( 1, dcl, 100 );
moveTo(xx,yy);
lineTo(xx+.1,yy+.1);
}
lineStyle( 1, 0x0, 35 );
moveTo(0,0); lineTo(0,height-1);
lineTo(width-1,height-1); lineTo(width-1,0);
lineTo(0,0); moveTo(0,originY); lineTo(width-1,originY);
moveTo(originX,0); lineTo(originX,height-1);
Код находится в отдельном файле coord.as и включается в первый кадр командой #include "coord.as". Имена функций нарочно имеют минимальную длину — моя фантазия подсказывает мне, что при рисовании удобно упаковывать побольше элементов в одну строку.
Теперь, чтобы проверить фишку, попробуем что-нибудь нарисовать. Построим тот же косинус… оба-на! For на 1000 итераций не работает! А все оттого, что мы беремся рисовать много точек в одном кадре — оно-то рисует, но кино не может обработать другие кадры, и все валится с ругательствами. Обходим: помещаем куски кода в разных кадрах:
1 #include "coord.as"
i=-3;
2 dt(i,Math.cos(i),0x0); i+=0.1;
3 if (i<=3) { GotoAndPlay(2); } else { Stop(); }
Чтоб дела шли быстрее, можно fps фильма разогнать до 120-ти. Теперь все работает как часы, точечки рисуются. А вдруг можно еще упаковаться? Без проблем: во втором кадре копируем строку — то есть по входу в кадр рисуются две точки сразу. Можно записать "оптимизатор" во втором кадре таким вот образом:
cnt=0;
while ((i<=3)&&(cnt<=100)) {
dt(i,Math.cos(i),0x0);
i+=0.01;
cnt++;
}
В результате наши расчеты не мешают воспроизведению остальной анимации, если таковая вдруг появится. Самый простой пример такой анимации — поле динамического текста, привязанное к переменной. Этот текст будет обновляться не чаще, чем мы будем переходить от кадра к кадру, так что это нужно периодически делать, если мы хотим отображать "бегущие счетчики", например, отрисованных точек.
Переходим к более сложным вопросам ActiveScript.
Об объектной модели ActionScript
Если вы привыкли работать с объектами в C++, то объекты в ActionScript частично окажутся для вас шокирующими. Для начала: вы привыкли к наличию классов и экземпляров? Придется отвыкать. Классы в ActionScript — это тоже экземпляры, только особого типа. Ну, собственно, если вы задумаетесь, как работают статические методы в классах C++, то поймете, что создавать экземпляр не всегда нужно. Если проводить параллель с ActiveX, то объекты-классы (объекты типа "класс") можно назвать фабриками классов.
Эта каша серьезно усложняет понимание, но не использование классов и объектов. Об объектах-классах также можно думать как о шаблонах, а о производных "экземплярах" как о копиях, создаваемых методом Clone(). Поэтому об объектах-классах еще говорят как об объектах верхнего уровня.
На самом деле вы будете часто пользоваться такими объектами верхнего уровня, предопределенными в самом Flash. Некоторые объекты вообще существуют в одном экземпляре, точнее — не являются экземплярами никаких классов, и создание новых копий не предполагается. На таком объекте выполняются только статические методы, хотя понятие статических методов, как таковых, в ActionScript, не существует.
К более привычным относятся два других типа объектов — "сточные" и пользовательские. Первые заранее определены, и вы обычно создаете их экземпляры. Например, вы создаете новый экземпляр snd=new Sound() для воспроизведения вашего саундтрека. Особый тип объектов, MovieClip, создается специальной функцией. Пользовательские классы создаете вы сами. И тут вас поджидает другой микро-шок.
Этот микро-шок — синтаксис декларирования класса. Его (синтаксиса) нет. Для определения класса используется слово function! Это уже жестоко напоминает "ООП" в perl: оказывается, все реализовано через области видимости, то есть класс определяется областью видимости локальных переменных и функций.
Это стало возможным потому, что, в отличие от C++ и в полном соответствии с Паскалем, допускается создание локальных функций внутри функций, так сказать иерархическая, а не одноранговая архитектура.
На еще более глубоком уровне зарыты локальные анонимные функции — то, что мы назвали бы виртуальными методами или указателями на функции. Эти функции доступны не по имени, а через "хэндлеры", в качестве которых выступают переменные, в частности — элементы списка. Именно так, через список дочерних функций, реализованы области видимости. Виртуальность заключается в том, что вы можете найти нужный метод и переопределить его, независимо от того, писали вы его сами или же унаследовали от суперкласса.
Сами функции, как можно уже догадаться, также являются объектами типа Function. Естественно, что функция содержит списки локальных объектов. Кроме этого функции содержат список своих аргументов (свойство arguments), ссылку на вызывающую и вызываемую функции (то есть на саму себя), а также несколько методов, вроде call и apply. Эти методы явно получают в качестве первого параметра ссылку на объект, из которого вызывается метод, и null, если это "свободная" функция.
Жара, однако, крепчает. Оставим на время эту теорию и проиллюстрируем ее практикой. Не простой, конечно, а относящейся к нашей задачке. Создадим класс, который вычисляет тригонометрические (впрочем, как и любые другие) функции, разделяя окружность на 2n частей. Впоследствии для любого положительного N возвращается значение в этой точке. Также можно спросить, какое "время" соответствует этому N. Параметры на входе конструктора: n, fn(){}, A, w. Где n определяет количество точек, функция задает вычисляемую зависимость, A и w — амплитуда и частота соответственно. Go-go.
function rev(n,fun,a,w) {
this.length=1<N;
this.mask=this.length-1;
this.values=new Array(this.length);
this.slice=Math.PI*2/this.length/w;
var i=0;
while (i<THIS.LENGTH) {
this.values[i]=a*fun(i*this.slice*w); i++; }
}
rev.prototype.GetValue=function(i){ return this.values[i&this.mask];}
rev.prototype.GetSlice=function(){ return this.slice;}
rev.prototype.GetLength=function() {return this.length;}
Вы, возможно, захотите спросить, почему я использую while, а не for. А потому что в for у меня проблемы. Может глюк, а может мне просто ума не хватает. В любом случае, в теории есть только три программных конструкции: последовательность, выбор и итерация — так что разницы никакой. Как видите, код компактный, на вид приятный (и при этом — работающий). Есть пару "хакерских" местечек, например вычисление той же битовой маски или "почему сначала делится на w, а потом умножается". Честно говоря, я и сам ничего не понимаю, просто это вот работает — значит угадал что-то.
Использование этого объекта такое (числа — номера кадров):
1 #include "coord.as"
#include "rev.as"
callback=function(arg){return Math.cos(arg);}
rev1=new rev(10,callback,1,1);
rev2=new rev(6,callback,2,2);
2 cnt=0;
while (cnt<REV1.GETLENGTH()*3) {
dt(cnt*rev1.GetSlice(),rev1.GetValue(cnt),0x00f);
Cnt++; }
3 cnt=0;
while (cnt<REV2.GETLENGTH()*3) {
dt(cnt*rev2.GetSlice(),rev2.GetValue(cnt),0x00f);
Cnt++; }
4 Stop();
Как видите, мы создаем два объекта, причем отличаются эти объекты тремя параметрами: порядком революции (количеством точек на оборот), амплитудой и частотой. Кроме того, мы проверяем три оборота, чтобы оценить, что наш объект корректно отсекает лишние биты и не ошибается при доступе к массиву. Графически результат выглядит так:
Наши объекты работают ожидаемым образом
Два глюка, кроме for, были обнаружены при работе с as-файлами. Во-первых, вы обязательно должны завершить последнюю строку переводом курсора — иначе ошибки, ошибки... Такие глупости когда-то встречались в некоторых утилитах UNIX — и, как видно, ходят по миру до сих пор. Второе — в режиме Ctrl+Enter какие-то вещи не меняются при изменении внешних файлов. То есть алгоритм обновления кэша включаемых файлов не работает как следовало было. Если ваши изменения в тексте программы не имеют эффекта, попробуйте проверять по Ctrl+F12 — должно сработать. Кстати, и производительность в браузере раза в два больше. Видимо, отключается какая-то отладка или что-то в том же роде.
Странные картиночки
Мы не будем детально обсуждать реализацию наших числовых методов, там все как в книжках. Важно то, что есть какая-то функция. На входе она воспринимает точку на плоскости, а на выходе дает следующую точку. Делов-то. Полный текст всех наших AS файлов — на КП-диске. В нашем "кине" код тоже не слишком сложен и похож на то, что мы уже видели:
1 #include "coord.as"
#include "rk4.as"
c=1.0; A=1.1; w=2.1; revN=8;
rk = new rk4(c,A,w,revN);
dots=1;
dotcolor=0x003300
2 for (i=0;i<500;i++) {
rk.NextPoint();
if ((rk.GetTI()&255)==0) {
dt(rk.GetX(),rk.GetY(),dotcolor);
dots++;
}
}
3 if (dots>100000) {Stop();} else {GotoAndPlay(2);}
Вот как один из наших странных аттракторов выглядит в результате.
Инь и Янь имеют простую математическую интерпретацию
Как видите, все очень красиво и похоже на ожидаемый результат. По сложившейся традиции все происходит на черном фоне. Аттрактора тут, собственно, два — в разных фазах. Фиолетовый соответствует нулевому смещению фаз косинуса, красный — полуобороту, углу Пи. Благодаря нашему табличному генератору делается все это просто.
Конечно, правильный препод должен сделать замечание, что, мол, на координатные оси не нанесены единицы измерения, кроме того, не указаны параметры. Серьезный программист, посмотрев в код, может дополнить, что координатную сетку тоже можно сделать объектом и параметризировать. К тому же, поскольку вычисления тут превалируют над отрисовкой, то несложно будет рисовать сразу 128 фазовых слоев в 128-ми окнах. Более того, можно эффективно анимировать слои, циклически заменяя символы MovieClip.
Да, все это так — но главное для нас не это. Куда интересней, что ActionScript может считать не хуже того же Бейсика — и при этом эффективно отображать результаты. Что и требовалось доказать. Кстати, вы легко можете кликнуть по клипу и прилизать любой участок — без единой строки кода. А теперь реализуйте это сами, например на C++… Ну, а мы пока будем продвигаться дальше.
А где же тут интерактивность и распределенные вычисления? Простой ответ: в Караганде. Более детально: Flash в современной форме включает все для интерактивности, реализованы основные элементы управления, а каких и нет — те можно добавить. Первое, что приходит в голову: позволить пользователю вводить параметры нашего уравнения и нажимать кнопку Пересчитать. Но это противоречит другой идее — распределенным вычислениям. В конце концов, можно сделать хотя бы кнопку Выход, для нетерпеливых.
Идея распределенного вычисления как раз и состоит в централизованном (или распределенном) управлении вычислительным процессом. Для реализации такого поведения проще всего создать на сервере XML-приложение, которое будет реализовать управление. Пользователю браузера при этом отводится роль лоха-наблюдателя.
В случае с нашим приложением можно предположить, что в качестве параметров будут выступать c, A и w. В качестве результата программа может сбрасывать те же параметры, плюс тип полученного графика: странный — не странный (придется еще реализовать детектор странности). Серверная часть легко сможет заносить эти данные в базу данных — с последующим анализом. Кстати, программа анализа этой БД тоже может быть написана на Flash, почему бы и нет.
С точки зрения программирования ActiveScript тут нет никаких проблем: в язык встроена поддержка XML-сообщений. Также в широком ходу и старая техника — LoadVariables. При этом вместо файла вы указываете имя CGI-скрипта, который и поставляет необходимые пары "имя-значение". Короче, даже выбор есть.
Выглядит это даже проще, чем кажется: например, для загрузки параметров из duffarg.pl можно загрузить переменные. Для этого достаточно строку
c=1.0; A=1.1; w=2.1; revN=8;
заменить на:
_root.LoadVariables(duffarg.pl,"GET");
Если скрипт генерирует параметры в виде XML, загрузить их будет чуток сложнее:
duffXMLParams=new XML();
duffXMLParams.onLoad=function(success) {
if (success) {
… Разбор XML документа
}
}
duffXMLParams.load(duffarg.xml);
Для "отдачи" результатов легко можно использовать метод XML.send() — отсылка работает еще проще, без ожидания результата. Несложно организовать и отсылку переменных, указав в качестве метода доступа "POST" либо же "PUT" — в качестве второго параметра LoadVariables().
Диагноз: Ш 7-Б
А теперь, если посмотреть на вещи прагматично, глазами конкретных людей из ЦРУ, ГРУ и других беспредельных заведений. Это мы для примера взяли какие-то странные аттракторы — а ведь эти-то ребята могут поручить Flash-скриптам все что угодно, от расчета биологического оружия, декодирования шифров, дешифрации изображений со спутников до вычитки электронной почты и… да мало ли хороших дел можно придумать.
И если раньше для этого нужно было покупать новый мэйнфрейм за несколько миллионов, то теперь достаточно перетереть с yahoo.com и разместить там свой Flash-банерок. Видели там такие большие Flash’ки? Это с виду там реклама кредитных карточек, а на самом деле — кто знает?
А ведь можно сделать "вычислитель" и вовсе маленьким и невидимым…
С другой стороны, можно, как в SETI@HOME, наоборот — разрекламировать, раструбить, чтобы любой пользователь мог поставить вашу флэшку домашней страничкой и таким образом стал помогать вам бороться со СПИДом, искать пришельцев и раскодировать коды террористов. Это уже вопрос наглости, под каким предлогом вы будете тырить у людей их процессорное время.
Кстати, ходит такая полусказка, что, мол, Саддам Хусейн в ответ на эмбарго на ввоз компов в Ирак скупал приставки Nintendo 64, ставил на них Linux, объединял в кластеры и решал стратегические задачки типа просчета траекторий ракет. Не уверен, что именно так оно и было — но идея, без сомнения, интересная. В любом случае, скрытые возможности есть, и рано или поздно они будут использованы.
Использованы иллюстрации с сайта astronomy.swin.edu.au.
Автор: Арсений Чеботарев
Источник: www.comizdat.com
|