javascript

Мир в бутылке: сжатие в картинку

Вчера я писал, что код и вероятности перехода в цепях Маркова упакованы в картинку, но не объяснил что это и для чего сделано.

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

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

Скриншот консоли: вывод сборки проекта bolklet, показывающий размеры файлов (JS, модель, спрайты), выбор формата PNG/RGB как оптимального и итоговое сжатие изображения на 89%.
Процесс сжатия в картинку — выбираем формат, который сжимает эффективнее

Сжатие при этом реализовывать в ДжаваСкрипте не нужно — браузер за нас распаковывается картинку, а мы её просто попиксельно читаем.

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

Оставить комментарий

Развернуть видео

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

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

document.querySelectorAll('*,iframe').forEach(e=>(e?.shadowRoot||e).
querySelectorAll('video').forEach(v=>v.style.transform = 'scaleX(-1)'))

Оставить комментарий

30 лет серверному ДжаваСкрипту!

Поздравляю всех фронтендеров с юбилеем серверного ДжаваСкрипта — ровно тридцать лет назад вышел Netscape Enterprise Server 2.0 с поддержкой технологии SSJS (Server-Side JavaScript).

Код можно было писать прямо внутри страницы (как в ПХП, например), оборачивая куски, выполняемые на сервере при помощи тега SERVER:

<SERVER>
write("Click a link to display an image:<P>")
cursor = database.cursor("select * from rockStarBios")
while(cursor.next()) {
    write(cursor.photos.blobLink("image/gif", "Image " + cursor.id))
    write("<BR>")
}
cursor.close()
</SERVER>

Позднее он на этом поле проиграл конкуренцию «Микрософту» и их технологии «Активных Серверных Страниц» (ASP), где можно было программировать на JScript (был такой диалект «ДжаваСкрипта») или VBScript и исчез с радаров.

Добавлено: оказывается я сам эту дату и раскопал, и даже в «Википедию» добавил.

2 комментария

Какой у вас GPU

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

Технически берётся параметр UNMASKED_RENDERER_WEBGL у контекста объекта WebGL.

GPU checker

_

×

У меня тут сейчас написано следующее:
ANGLE (Apple, ANGLE Metal Renderer: Apple M3 Max, Unspecified Version)

У братишки на рабочем компьютере (там «Виндоуз»):
ANGLE (Intel, Intel(R) UHD Graphics 770 (0x0000A780) Direct3D11 vs_5_0 ps_5_0, D3D11)

На моём смартфоне «Сяоми 14 Ультра»:
Adreno (TM) 750

Добавлено: как справедливо заметили в комментариях в телеграмном канале, это странно, что браузер позволяет так точно определить эту информацию, посколько производители браузеров часто борются с идентификацией браузера, а тут информация, которая позволяет производить идентификацию точнее.

6 комментариев

JavaScript™

Поразительно! Сегодня я узнал, что «JavaScript» — зарегистрированная торговая марка, принадлежащая компании «Оракл». Она попала к «Ораклу» вместе с другими активами компании «Сан Микросистемс» при её поглощении в 2010-м году.

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

Автор Node.js пытается добиться отмены регистрации торговой марки, аргументируя это повсеместным использованием этого названия. Прецеденты есть, насколько я знаю, может и получиться.

Другим выходом из ситуации было бы ещё переименование языка в EMCAScript или в LiveScript — оба названия имеют отношение в ДжаваСкрипту. Но этот путь, как мне представляется, сложнее первого.

11 комментариев

Атрибут LANGUAGE

Просматривал тут публичные репозитории некого соискателя одной из наших вакансий, обратил внимание, что у него там, помимо всего прочего, лежат решённые задания со «Стэпика». Заглянул из любопытства, никаких особенных выводов не сделал, но удивился, что в тегах одного задания у него script содержит атрибут language. Это что же, его до сих пор учат писать?

Мне стало любопытно — он вообще сейчас какое-то значение имеет? Браузеры на него ориентируются? Когда-то он вполне имел смысл — у «Эксплорера», например, там мог стоять VBScript или, например, JScript.Encode — зашифрованный текст программы на ДжейСкрипте, это такой диалект ДжаваСкрипта от Микрософта.

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

А что же считается верным значением для ДжаваСкрипта? В угадайку играть не хотелось, скачал исходники «Хромиума», посмотрел что там используется. Как оказалось, подставить можно следующие значения (регистр значения не имеет):

  • javascript или x-javascript — это понятно, единственный сюрприз, что можно поставить «экс» перед словом;
  • ecmascript или x-ecmascript — тоже понятно, ДжаваСкрипт — расширение этого языка;
  • jscript — диалект языка в «Эксплорере», считается, что другие браузеры сейчас его тоже «знают», хотя на деле есть нюансы, но всем уже всё равно;
  • от javascript1.0 до javascript1.5 — когда-то указанием версии можно было разделять скрипты по уровню поддержки языка в браузере;
  • livescript — старое название языка «ДжаваСкрипта», я ещё помню времена, когда это значение использовалось, хотя и редко.

Сейчас, конечно, это скорее археология, чем какое-то нужное знание.

DoomPDF

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

Но «Дум», запущенный внутри PDF-файла, меня чертовски удивил! Не то, чтобы я не знал, что это возможно — в конце-концов, PDF сам по себе программный файл (там внутри язык программирования PostScript), но я как-то даже и не думал о такой возможности.

Вы попробуйте, работает даже внутри браузера!

Скриншот интерфейса DoomPDF: пиксельный вид из игры, панель управления с кнопками (esc, use, enter, fire), список команд инициализации и описание управления клавишами WASD.

Правда, в данном случае PostScript почти не использовался. Всё дело в том, что внутри PDF есть возможность использовать ещё и JavaScript. Причём, в случае Adobe Acrobat, доступны, например, такие, сомнительные для PDF возможности, как 3Д-графика или HTTP-запросы.

В просмотрщиках PDF современных браузеров поддержка JavaScript тоже есть, правда она сильно ограничена по функционалу. Тем не менее, для запуска «Дума» хватило и этого.

Чтобы запустить «Дум» внутри PDF, использовался старый Emscripten, который компилирует код на Си в asm.js (это такое подмножество JavaScript), вместо более привычного WebAssembly. Но этого недостаточно — нужно было придумать, как принимать ввод с клавиатуры и отображать графику. Это оказалось не таким уж и простым. К счастью, в браузерах PDF-движки поддерживают текстовые поля и кнопки, что и было использовано для ввода.

С графикой возникли следующие проблемы. Речь идет о разрешении 320×200 пикселей, что означает, что если бы использовались обычные текстовые поля для каждого пикселя, пришлось бы обновлять тысячи полей на каждый кадр. В общем, так бы вы никогда не поиграли в «Дум». Вместо этого автор решил использовать одно текстовое поле на каждую строку экрана и обновлять их с помощью ASCII-символов. Простой, но довольно эффективный способ, который дает в итоге монохромную картинку с шестью цветами. Конечно, такой способ тоже не даёт плавного рендера картинки, но играть всё равно довольно комфортно!

4 комментария

UnSnow 2

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

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

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

// ==UserScript==
// @name         UnSnow
// @author       Evgeny Stepanischev aka Bolk
// @version      2024-12-31
// @namespace    /files/unsnow2.js
// @description  Turn off stupid snow
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    if (window.location.hostname === 'aliexpress.ru') {
        return;
    }

    Array.from(document.querySelectorAll('*')).forEach(e => {
        for (let a of e.attributes) {
            if (/(?<!un)snow/i.test(a.name + a.value)) {
                e.style = 'visibility:hidden;position:absolute;margin-left:-10000px;' +
                          'display:none;transform:translateX(-100vw);opacity:0';
            }
        }
    });
})();

2 комментария

Посещал ли пользователь сайт?

Атака не работает — в браузерах давно реализована защита, у меня идея «сработала» в силу того, что я не выполнил все необходимые проверки.

В прошлом было достаточно много методов определить ходил ли пользовать на какой-то сайт или нет. В основном, идея была проста: у себя на сайте через CSS каким-то способом выделяем посещённые (:visited) ссылки — например, делаем таким ссылкам шрифт больше, а потом через ДжаваСкрипт смотрим у каких ссылок ширина стала больше расчётной.

Это считалось проблемой, поэтому свойство изменили так, чтобы никакой утечки информации о посещении в ДжаваСкрипт не происходило. Все современные браузеры уже много лет от этого защищены.

Но недавно меня осенило, что есть способ обойти эту защиту!

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

Я попробовал сделать это с «Гитхабом». Самый большой файл, который загружается там с первой страницей — vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_primer_octicons-react_di-b40d97-9b98c5140e22.js. Занимает он 136 килобайт, вполне подходящий размер.

Как же определить момент когда он загрузится? Если посмотреть внутрь, видно, что он после скачивания создаёт свойство webpackChunk в объекте globalThis. Если перехватить обращение к этому свойству, можно понять, что файл загружен:

const t = new Date();
Object.defineProperty(globalThis, 'webpackChunk', {
  set: function() {
    console.log(new Date() - t);
  }
});

Ниже этого кода подключаем загрузку указанного файла прямо с «Гитхаба» через тег <script> и дело в шляпе.

Я проверил, если очистить кеш браузера, то файл у меня загружается примерно за 100—400 миллисекунд, если берётся из кеша — это 0—12. Легко отличить одно от другого.

10 комментариев

Сложности проверки версий

Случайно обратил внимание какое-то время назад, что у меня на сайте почему-то перестало проигрываться аудио в формате MP3 в «Опере», моём основном браузере. Никак не доходили руки разобраться, но в эти длинные праздники я всё-таки докопался до сути. Суть оказалось смешной до нелепого.

Дело в том, что в движке, который я использую для своего дневника, для проигрывания аудио используется библиотека «Жуэль», а её текущая версия, в свою очередь использует старую версию библиотеки «howler.js», в которой есть вот такой код:

self._navigator = (typeof window !== 'undefined' && window.navigator) ? window.navigator : null;
var checkOpera = self._navigator && self._navigator.userAgent.match(/OPR\/([0-6].)/g);
var isOldOpera = (checkOpera && parseInt(checkOpera[0].split('/')[1], 10) < 33);

Проблема в регулярном выражении OPR\/([0-6].) и в версии «Оперы». Недавно версия перевалила за 100 и эта регулярка, вместо корректного номера, стала возвращать «10».

Из-за этого третья строка считает мою «Оперу» слишком старой (потому что 10 меньше 33), чтобы поддерживать проигрывание файлов MP3.

Заменил у себя на сайте howler.js на актуальную версию и всё заработало. Заодно предложил патч в «Жуэль», надеюсь примут оперативно.

4 комментария

Какие ещё графические форматы поддерживает ваш браузер?

Переложил на хостинг «Гитхаба» свой проект семилетней давности — «Какие графические форматы поддерживает ваш браузер?». Я его иногда обновляю и мне было бы проще это делать через репозиторий.

Из всего, что я там проверяю, сразу не сработала только проверка на AVIF — это новейший формат, у меня на компьютере его поддерживает пока только «Файерфокс», ему важно указание типа содержимого, а «Гитхаб» передаёт неправильное значение.

Скриншоты браузеров: список поддерживаемых форматов изображений (JPEG, PNG, SVG, WEBP, BMP, GIF, TIFF, ICO, AVIF и др.).
Браузеры (сверху вниз): «Сафари» 13, «Файерфокс» 78 и «Опера» 69

Я подумал, что наверняка есть какой-то способ указать правильный тип в файле конфигурации сайта, но нет, так это не работает, такой настройки в нём нет. В принципе, известно откуда «Гитхаб» берёт свою базу типов содержимого — из проекта mime-db. Но этот путь тоже не сработал — я добавил туда тип для AVIF больше недели назад, но ничего не изменилось. Видимо синхронизация изменений происходит нечасто.

Пришлось идти другим путём — вместо того, чтобы загружать файл картинки, внедрил его внутрь при помощи протокола data:, это позволило обойти проблему. Можете протестировать на своём браузере.

Ссылка на проект: https://bolknote.github.io/detect-browser-graphics-formats/
Ссылка не репозиторий проекта: https://github.com/bolknote/detect-browser-graphics-formats

7 комментариев

JUnix в книге

Пока ещё далеко не ушёл от этой темы, напишу.

Недавно выкладывал в открытый доступ свой проект начала нулевых — JUnix, «эмулятор» Линукса на ДжаваСкрипте. Заодно для интереса погуглил много ли ссылок осталось на прежний сайт проекта — junix.kzn.ru.

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

Книга, как оказалось, всё ещё выпускается и продаётся, правда есть ли в переизданиях упоминание «ДжУникса» выяснить не удалось — онлайн-магазины нужную главу не показывают, а тратить тысячу рублей на её покупку только ради этого мне не хочется.

Страница учебника про эмуляторы Unix: заголовок 9.2, текст о JS-эмуляторе Степанищева, скриншот входа (JS Unix emulator v5.48b, IE 5.01, логин Alex) и пример man ls.
Упоминание JUnix в книге «Операционные системы. Практикум. Учебное пособие», Назаров С.В., Гудыно Л.П., Кириченко А.А.

К слову, это не первая книжка, на страницы которой попал «ДжУникс». Первой была моя зачётная книжка. Поскольку во время увлечения этим проектом к учёбе я относился с прохладцей, пришлось совмещать приятное с полезным, и защищать «эмулятор» в качестве курсовой — как среду для обучения студентов операционной системе «Линукс».

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

2 комментария

JUnix ★

Вкратце: выложил на гитхаб свой старый проект «эмулятора» Линукса, который я писал в 90-е и начале 2000-х

В 90-е мало кто видел потенциал применения ДжаваСкрипта в браузерах, тогда он, в основном, использовался для несложного интерактива — покрасить кнопки при наведении мышкой и прочие задачи того же уровня.

Мне тогда этот язык невероятно нравился, я был в бешеном восторге и такое вот несерьёзное к нему отношение меня очень задевало. Как-то я фантазировал на тему того, что можно было бы такого интересного сделать в браузере, чтобы показать значимость ДжаваСкрипта, и как-то мало-помалу в голову пришла идея запрограммировать эмулятор «Линукса» — я как раз активно изучал эту ОС в те годы.

Эта фантазия меня так увлекла, что примерно год я посвящал ей все вечера, в ущерб учёбе в Университете и личной жизни. Позже я ещё долго возвращался к этому проекту, правда моя активность всё угасала, пока в 2003-м году я не забросил эмулятор окончательно.

Скриншот терминала Unix-эмулятора JUnix v5.52b с командами whoami (root), df и mount, показывающими файловые системы и их параметры.
Старый, пыльный JUnix в современном браузере. Пришлось немного повозиться, чтобы запустить

Конечно настоящий эмулятор у меня не получился, да я и не пытался его создать, получилась имитация командной строки «Линукса» на том уровне знаний, который у меня был в те годы.

Реализованы кое-какие горячие клавиши, работа с историей и буфером обмена, основные команды (список выводится по команде «?»), перенаправление ввода-вывода, «пайп», работа с переменным, ветвления и циклы, виртуальная файловая система с возможностью написания плагинов и многое другое.

Поскольку шеллом по-умолчанию у меня тогда был tcsh, некоторые конструкции выглядят непривычно, кроме того, ряд команд я просто неправильно понимал и реализовал в соответствии со своими заблуждениями.

В своё время появление этого «эмулятора» понаделало шуму — о нём написали все основные российские сайты про программирование, а я каждый день получал письма от тех, кому понравилась моя игрушка.

Постепенно домен, на котором это всё располагалось, потерялся, а потом со старым винтом умер и бакап сайта. Осталась только копия в «Веб-архиве».

Так бы он там и лежал, но вчера в разговоре Леонидом Кагановым я случайно помянул почивший проект и Леонид, который его моментально вспомнил, предложил забрать сохранившееся с «Веб-архива» и куда-нибудь выложить.

Честно говоря, я и сам давно об этом думал — всё-таки, учитывая сколько души и времени вложено в этот «эмулятор», у меня с ним связано много хороших эмоций.

И вот вчера я наконец выкачал слепок первой попавшейся качалкой, поправил очевидные баги, чтобы всё заработало в современных браузерах — они всё-таки ушли далеко вперёд за это время, немного почистил от мусора и залил на «Гитхаб».

Кстати, если вам нравится в таком копаться, можете посмотреть сколько костылей в то время приходилось городить и как беден был раньше этот ДжаваСкрипт.

Я потестировал кое-какие основные команды, как будто теперь всё работает, но это не точно — всё-таки внутри больше пяти тысяч строк нетривиального кода без юнит-тестов. Интересующихся приглашаю ознакомиться с проектом по ссылкам ниже.

Репозиторий проекта: https://github.com/bolknote/junix.
Сайт проекта, где можно посмотреть всё в действии: https://bolknote.github.io/junix.

2 комментария

JavaScript и иврит

Код на JavaScript: присваивание переменным 1–8 значений в виде греческих букв (α, β, γ, δ, ε, ζ, η, θ) с комментариями на английском языке.

Выше прекрасный способ сломать мозг стыком трёх языков — английского, иврита и ДжаваСкрипта.

Как многим известно, в семитских языках текст записывается справа налево. Когда я лет 20 назад участвовал в разработке сайтов для некой арабской страны, это был тот ещё вызов моему внутреннему набору аксиом. Прокрутка слева, выделение текста в другую сторону, клавиша Backspace стирающая в противоположную сторону от стрелки, которая на ней нарисована, и прочие прелести.

Тогда кажется только Эксплорер умел поддерживать такое и переключался он атрибутом dir целиком, всем окном. Сейчас у нас есть Юникод и специальные коды смены направления текста. В одной строке можно сколько угодно его менять.

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

Дополнение: в комментариях меня поправили. Оказывается коды смены направления тут не нужны — программы автоматически меняют направление, основываясь на том символы какого языка используются, просто в этот момент захватываются ещё и небуквенные символы — пунктуация, цифры и так далее.

3 комментария

Банан велик, а кожура еще больше

Много когда-то программировал на ДжаваСкрипте, поэтому многие его «особенности» просто заучил наизусть, даже не утруждая себя детальным пониманием почему и как это работает. В свою защиту хочу сказать, что многие вещи там просто «исторически сложились»

А тут братишка прислал в «Телеграм» кусок кода, который всплывает на «Стек Оверфлоу» не первый год:

console.log(0 >= null); // выведет true
console.log(0 > null || 0 == null); // выведет false

Странное поведение, как ни крути, ведь даже название операции «больше или равно» раскладывается на две — либо «больше», либо «равно». Казалось бы оба варианта должны давать одинаковый результат.

Решил я полюбопытствовать есть ли объяснение этому феномену.

Во всех браузерах работает одинаково странно, а это значит, что где-то в стандарте должно быть детально описано это поведение. И действительно, вот это место:

Let r be the result of performing abstract relational comparison lval < rval
If r is true or undefined, return false. Otherwise, return true

Что означает примерно следующее: если нам надо выполнить операцию «lval >= rval», то мы должны её преобразовать в «!(lval < rval)». То есть «0 >= null» преобразовывается в «!(0 < null)», результат операции внутри скобок — false (так как «ноль» не меньше, чем null), что после отрицания даёт нам true. Всё просто.

8 комментариев

Что есть истина?

У нашего бывшего сотрудника в фейсбуке увидел ссылку на любопытную задачку — может ли (a == 1 && a == 2 && a == 3) быть «истиной» в ДжаваСкрипте?

Не заглядывая в статью, я предложил два варианта, вполне очевидный первый:

a = ((counter) => ({valueOf:() => ++counter}))(0)
// {valueOf: ƒ}
a == 1 && a == 2 && a == 3
// true

И второй — на суррогатных парах. Но по ссылке есть ряд других занимательных способов — через геттеры, похожие символы Юникода (мне приходил в голову такой вариант, но я не смог подобрать три символа, одинаковых на вид), другие специальные методы и прочее. Больше всех мне понравился такой способ:

a = [1,2,3];
a.join = a.shift;

a == 1 && a == 2 && a == 3
// true

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

2 комментария

Что-то не вижу — быть или не быть?

Программа, выводящая монолог Гамлета (19.86КиБ)
Так выглядит программа, выводящая монолог Гамлета

Слово «выглядит» в подписи ко скриншоту выше упомянуто неслучайно — программа написана так, что видимое — только надводная часть айсберга.

Уже в те далёкие времена, когда я только ещё начинал писать на ДжаваСкрипте, программисты на форумах задавались вопросом можно ли как-то защитить свои программы на этом языке от обратной разработки. Помню «Микрософта» в своём браузере позволяла шифровать исходный код, но эту «защиту» довольно быстро поломали, очень уж она была простая.

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

С тех пор эти инструменты застыли примерно в том же состоянии, но теперь, мне кажется, в этом деле наметился прорыв.

Некто ФейкЮникод, разместил скрытое послание внутри суррогатных пар Юникода. Я когда-то делал что-то похожее на пробелах нулевой длины, но моим способом сильно не разбежишься — алфавит маленький.

Что такое суррогатные пары расписывать не буду, статей на эту тему предостаточно, главное, что их не видно и они могу быть частью (кроме первого символа) любого идентификатора ДжаваСкрипта.

Я попробовал использовать способ с суррогатными парами, чтобы скрыть монолог Гамлета внутри программы на ДжеЭсФаке (способ написания программ на ДжаваСкрипте, когда не используются алфавитно-цифровые знаки), плюс этими же парами закодировал имена переменных.

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

16 комментариев

F★ckJS на поло

Белая футболка с надписью «ПРАКТИКА» и кодом var phone = ... на фоне стола с зелёным держателем для ручек.
Поло с программой на ДжаваСкрипте, написанной четыре года назад

Очень в тему к предыдущему посту на работе нашёлся мешок с поло размера XXL (из-за размера и сохранился, остальные разобрали).

На поло программа на ДжаваСкрипте, которую я писал к какому-то событию, должно быть готовились к какой-то конфереции — если её запустить в консоли браузера, появляется надпись «prihodite rabotat 88002005221». У меня в «исходящих» сохранилось письмо от 11 марта 2013 года, где я высылаю оригинал этой программы нашему дизайнеру, четыре года уже прошло, надо же.

2 комментария

«Странный» JS

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

[] + [] // массив + массив
"" // результат — пустая строка

[] + {} // массив + объект
"[object Object]" // В результате получаем объект? Ну ок

{} + [] // объект + массив
0 // 0? Реально?

{} + {} // объект + объект
NaN // Not a Number? WAT?

Выглядит очень всё ооочень странно, если думать, что происходит именно то, что написано в коментариях справа. На самом деле происходящее неверно интерпретировано авторами.

В ДжаваСкрипте фигурные скобки, помимо объекта, задают ещё и блок кода. В данном случае все «объекты» слева — на самом деле блоки кода. Откроем консоль и попробуем это доказать:

Вот что происходит на самом деле (9.90КиБ)

Как видите, в левый блок можно без труда добавить код и станет очевидно, что это не описание объекта. Так два последних обсуждаемых примера распадаются на две независимые команды — определение пустого блока кода, который ничего не выполнит и унарную операция «плюс» над пустым объектом или массивом.

С массивом, возвращающим пустоту при суммировании (конкатенации) всё ещё проще — в данном случае производится попытка вызвать метод toString, который у массива выводит строку его значений через запятую. Так как значений нет, строка пустая.

В общем, ничего сильно странного не происходит.

42 комментария

Как скачать документ из АИС ЦГАСО-2

Самарский архив видимо что-то у себя обновил и предыдущий способ для скачивания документов оттуда работать перестал. Очень жаль, удобство работы с интерфейсом архива оставляет желать лучшего, не говоря о скорости доступа к документам.

С просьбой что-то с этой проблемой сделать, мне написало около десятка человек, сегодня у меня наконец дошли руки посмотреть что изменилось. Как и в прошлый раз надо открыть окно консоли браузера и запустить скрипт (я проверял его в «Хроме»). Плохие новости в том, что скрипт будет работать относительно неспешно — 400 страниц обрабатывается примерно за 5—6 минут.

В конце работы в консоли будет длинная строка, начинающаяся с «dxo.itemsValue» и заканчивающаяся на «];». Её, как и в прошлый раз, надо будет скопировать в файл и передать в параметрах программе.

!function () {
    var id = '[id$=seadragonContainer] div div';
    var bt = '[id$=ForwardBtn]';
    var pages = {};
    var o = document.querySelector(id);

    !function _observe(undefined) {
        var ob = new MutationObserver(function() {
            var imgs = $(id+' img[src*=Pages]:first');
            if (imgs && imgs[0]) {
                var page = imgs[0].src.match(/id=([^&]+)/)[1];
                if (pages[page] == undefined) {
                    pages[page] = true;

                    ob.disconnect();

                    var next = $(bt);
                    if (next && next[0]) {
                        _observe();
                        next[0].click();
                    } else {
                        console.clear();
                        console.log("dxo.itemsValue=['" + Object.keys(pages).join("','")+"'];");
                    }
                }
            }
        });

        ob.observe(o, { childList: true, attributes: true, subtree: true });
    }();

    o.setAttribute('start', true);
}();

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

Внимание: скрипт должным образом я ещё не протестировал (просто не успел), так что на корректную работу пока не рассчитывайте!

45 комментариев

← 1 2 3 4 5 6 →