← All posts tagged идиотизм

Обожаю читать Гранта Скиннера: столько перлов даже у "профессионалов" с флэшер.ру не встретишь =)
вот свежачОк: github.com

казалось бы ну что тут такого?
нет, блядь, чувак не может сделать func.apply( target, params ) перед вызовом, надо обязательно хуйнуть и функцию и параметры в другой метод, что бы свершилось там! гениально!

дальше ещё веселее:
o.f.apply(o.scope, [eventObj]);
конечно, сука, мозг заточен на хуету, поэтому вместо того что бы сделать call, он создаёт лишний массив и делает apply. COOL!

СКИННЕР, ДОЛБАЁБИНА, ХАРЭ ПРОГРАММИРОВАТЬ! ТЫ, БЛЯДЬ,УЖЕ СТАРЫЙ ПЕРДУН! ЕСЛИ ДО СИХ ПОР НЕ НАУЧИЛСЯ ПИСАТЬ КОД, ТО УЖЕ НЕ НАУЧИШЬСЯ! МЫ ВЫРОСЛИ НА ТВОИХ КОМПОНЕНТАХ ДЛЯ ФЛЭША! И МЫ ЖАЛЕЕМ ОБ ЭТОМ! ВЕСЬ МИР ХОТЕЛ РАЗБИТЬСЯ ОБ МОНИТОР ЛИЦОМ, КОГДА ПОЛЬЗОВАЛСЯ НА ПРОТЯЖЕНИИ ДОЛГИХ ЛЕТ ТВОИМИ КОМПОНЕНТАМИ! МЫ ПОНИМАЕМ, С ХУЯ ЛИ ТЫ СВАЛИЛ В JAVASCRIPT, ПРОСТО ТЕБЕ ВЕСЬ МОСК ( ИЛИ ЧТО ТАМ У ТЕБЯ В МЕСТО НЕГО ) ВЫНЕСЛИ, И ДО ТЕБЯ ДОШЛО ЧТО ACTIONSCRIPT — НЕ ТВОЁ. НО ТЕПЕРЬ ТЫ ПРИПЁРСЯ В ДРУГОЙ ЯЗЫК... НА ТЕБЯ СМОТРЯТ И СО СЛЕЗАМИ ХИХИКАЮТ: "ДА ФИГЛИ, ОН ЖЕ ФЛЭШЕР". НЕ ПОЗОРЬ БРАТВУ, ЧМО! ТЫ ОПЯТЬ ПОПУЛИЗИРУЕШЬ СВОЁ КРИВО РАБОТАЮЩИЕ ГОВНИЦО. ТЫ ПИШШЕШЬ ЕГО УЖЕ ВТОРОЙ ГОД, И ПРИ ЭТОМ НЕ ЗАМЕЧАЕШЬ ОЧЕВИДНЫХ БАГОВ. СРЕДНИЙ ДЖАВАСКРИПТЕР НАПИШЕТ ТОЖЕ САМОЕ ЗА ПАРУ ДНЕЙ.

УЙДИ КРАСИВО, ОТКРОЙ ГЛАЗА И ПОЙМИ: ТЫ НЕ УМЕЕШЬ ЕБАШИТЬ ЧЁТКИЙ, ПАЦАНСКИЙ И ГЛАВНОЕ РАБОТАЮЩИЙ КОД. СЪЕБИ С ПРОСТОРОВ ИНТЕРНЕТА И УДАЛИ ВСЮ ИНФУ О СЕБЕ, КОТОРУЮ СМОЖЕШЬ.

СУКА.

давно ничего не писал. сейчас буду ругать таймеры.

давным давно, когда мы писали самое настоящее ММО с блэкджеком и перьями, нам приходилось синхронизировать действия на клиенте с действиями на сервере. для этого использовался не хитрый механизм синхронизации при входе в игру.
со временем мы начали получать репорты о том, что у некоторых пользователей после десяти минут в игре действия на экране начинают происходить со значительной задержкой. сперва мы думали, что во всём виноват пинг или лаги сервера, но потом репортов стало чуть больше чем много и мы забеспокоились.
начали тестировать и проблема долго не наблюдалась, пока однажды во время тестов мы не свалили на обед, оставив игру запущенной. вернувшись мы таки увидели задержку на реакцию в ~4 секунды. оставив на ночь мы получили задержку почти в минуту.
разбирая на кусочки всю игру мы поняли, что ошибка спряталась в методе getTimer. тот бесстыдно отставал от реальных часов. характер отставания был не понятен. после ряда наблюдений было установлено, что на разных компах время может как уходить вперёд, так и отставать с течением времени.
с тех пор прошло года три, но проблема всё ещё актуальна.

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

код решения есть тут: flasher.ru

вчера весь день и ночь ковырялся с конкурирующим жесоном ( blog.brokenfunction.com ). его енкодер по непонятным мне причинам оказался быстрее. я вычислил, что у него очень упрощённая версия версия. но даже добавив в его код соответствующий функционал, мне не удалось его обогнать. начал разбираться со своим кодом.
итог: именно при кодировании жесона работа с памятью медленнее чем прямая запись в ByteArray. пока не понял почему =(

при попытки использовать instanceof, вам вывалится ворнинг, о том что нехер юзать всякие депрекейтед и пора начать юзать пацанский is.
всё бы ничего, но is требует тип Class, что в моём случаи меня не устроило. я подумал, что они просто чутка ошиблись ( бывает ) и подсунул ему Function с помощью wild card. расстроился, так как он всегда возвращает true, даже если на самом деле там должен быть false. при этом instanceof работает абсолютно корректно, но вываливает ворнинг.

что делать?

понадобилась быстрая операция подсчёта остатка отделения. я вспомнил, что где видел мегабыстрое деление. собственно видел я его тут: haxe.org
изучил и решил протестить у себя. запускаю. 95% случаев результат печальный. обычное деление чуть ли не в 3 раза почти всегда быстрее. думаю: как же так??? полез изучать их бенчмарк и нашёл охуенчик!
в случае с тестом их "быстрого деления" используется локальная перменная, а в случаи с обычным — свойство класса =) зашибись бенчмарк.

наконец удалость составить короткий пример проявления бага #785401

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

package {

import flash.display.Sprite;
import flash.utils.ByteArray;

public class test extends Sprite {

/**
* Constructor
*/
public function test() {
super();

// запускаем многократные тесты
for ( var i:uint = 0; i<10; i++ ) {
trace( '================== test ' + i );
binary_test();
}

}

private static const LENGTH:uint = 5e3;

private static function binary_test():void {

// создаём новый бинарник
var bytes:ByteArray = new ByteArray();

bytes.writeUnsignedInt( 10 ); // делаем запись
bytes.length = LENGTH; // меняем длинну

// проверяем что у нас лежит в бинарнике
var i:uint = 4;
do {

if ( bytes[ i ] != 0 ) {
trace( 'index: ' + i + ', value: ' + bytes[ i ] );
}

} while ( ++i < LENGTH );

// заполняем бинарник
i = 4;
do {

bytes.writeInt( i );

i += 4;
} while ( i < LENGTH );

bytes.clear(); // чистим

}

}

}

если менять местаим эти 2 строчки, то бага исправляется

bytes.writeUnsignedInt( 10 ); // делаем запись
bytes.length = LENGTH; // меняем длинну

сижу я, значит, пишу обновлении для своей крипто-библиотеки ( #755847 ), и случайно вывожу на экран 2 результата от 2 запусков PNGEncoder.
первый вариант 100% совпадает с оригиналом, а второй был слегка искажён. я сперва не сообразил, что произошло, а потом пришёл в состояние шока. решил добавить ещё парочку результатов, и получил, ещё более искажённые результаты.

flasher.ru

начал искать искать ошибки у себя в коде: переиспользование переменных; проверял везде ли чиститься память; заменял одни вызовы другим, но результат становился чаще хуже, чем лучше.
на протяжении всех 10 часов паники я общался с wvxvw ( flasher.ru ), и мы вместе пытались понять причину, но не ничего не выходило.

в конце концов в один из блоков я вставил код проверки на записанное значение в ByteArray. и оказалось, что там на 88731 индексе уже записано число отличное от 0.
глаза мои вылезли на орбиту: ведь этот массив был создан всего 2мя строчками выше, и в него ничего не писалось кроме одного числа в нулевой индекс! то есть фактически он был пуст.

передвинув проверку на строчку выше я удивился ещё больше, так как не только trace оказался чист, но и картинки отобразились корректно.
немного поигравшись с перемещением срок, я убедился, в зависимости бага от положения строк.

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


var b:ByteArray = new ByteArray();
b.writeUnsignedInt( value );
b.length = 1024; // может попасться мусор


var b:ByteArray = new ByteArray();
b.length = 1024; // мусора не будет
b.writeUnsignedInt( value );


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

я тут задумался о ситуации с приватами в php ...
где-то я видел такие вот реализации:

вбиваешь в адресной строке что-то типа site.com

а в пхп происходит следующие:

создаётся экземпляр класса controler и вызывается у него метод method с передачей в него параметра arg.

выходит, что если я это на хаксе напишу, то у меня весь код — это сплошная injection уязвимость.
забавная идиология =) точнее идиома.

циклы, сцуко, коварны ...
при использовании загадочных for'ов и inline-методов надо быть острожным. загадочный компилятор хакса для своих тайных нужд, при сочетании этих двух слов создаёт локальную переменную, в которую записывает значение класса.

class A {

static inline function aaa() {
// <-- вот тут всовывается var loc_0:* = A;
var i:Int;
for ( i in 0...10 ) {
}
}

}

соответственно могут возникнуть неприятные последствия, при попытки сделать exclude классу A.
в общем пришлось отказаться в пользу while, с которым такого не бывает.

Дениска ( etcs.ru ) меня сегодня порадовал ещё раз:

public function test()void {
var a:String;
trace( typeof a ); //string
}

в чём же прикол? по логике в a записан null а значит результатом должен быть object, но мы наблюдаем string.

оказывается компилятор превращает это вот такой вот код:

_as3_pushnull
_as3_coerce_s
_as3_setlocal <1>
_as3_findpropstrict trace
_as3_pushstring "string"
_as3_callpropvoid trace(param count:1)

в хуманабельном виде это выглядит так:

public function test() : void {
var _loc_1:String = null;
trace("string");
return;
}

тоесть копилятор оптимизирует выражение typeof a до выражение string, но этот же копилятор не умеет оптимизировать математические выражения =) лол.

вот мне интересно как так устроенно AS3 API, что оно так странно работает? :)

простейший ( и при этом широко известный ) пример:

while ( numChildren ) {
removeChildAt( 0 );
}

этот код работает быстрее чем:

var i:int = numChildren;
while ( --i ) {
removeChildAt( i );
}

парадокс. казалось бы удаление последнего элемента массива должно занимать меньше времени чем первого, да и обращение к локальной переменной должно быть шустрее, чем к свойству объекта. ан-нет! нефига. устройство данной конструкции остаётся загадкой.

но при этом у нас есть 2 метода:

getDefinitionByName
getClassByAlias

объясните мне идиоту, почему приходится писать обёртки для этих методов? что в них такого страшного происходит, что приходится делать локальные хэши?
в результате через такой метод всё работает в N раз быстрее.

function get(name:String):Object {
var result:Object = _hash[ name ];
if ( !result ) {
_hash[ name ] = result = getDefinitionByName( name );
}
return result;
}

в чём ваще проблема сделать это на нативном уровне?

почему эти методы кидают исключение а не возвращают null? и как мне избегать исключения, если у меня нету метода hasDefinition, hasClassAlias?
точнее с дефинишем я, конечно, вру слегка. проверить можно так:
ApplicationDomain.currentDomain.hasDefinition
но если так проверять, то проще запросить тогда
ApplicationDomain.currentDomain.getDefinition
ведь последний метод возвращает null как и положено =)

p.s.: я не любитель try..catch, и всегда стараюсь избегать их используя if..else, если есть такая возможность.