В разделе программирование
Андрей Баксаляр  :: 21 апр 2016, в 22:05

При использовании jQuery (или подобной JavaScript-библиотеки) мы часто сталкиваемся с необходимостью проверить — существует ли элемент или узел DOM в документе? Конечно, для этого удобнее было бы использовать еще и привычные CSS-селекторы.

Первое, что приходит на ум - это проверять, возвращает ли jQuery объект при попытке выбрать его селекторами. Например, так:

if ($("#mydiv")) {
    // полезный или бесполезный код
}

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

Однако, благодаря тому, что объект возвращается пустым, появляется и элегантное решение проблемы. Ведь можно банально получить длину объекта через его свойство length:

if ($("#mydiv").length > 0){
    // полезный или бесполезный код
}

Можно еще немного упростить решение:

if ($("#mydiv").length) {
    // полезный или бесполезный код
}

Теперь условие будет работать корректно, потому что когда jQuery возвращает пустой объект, его длина будет равна нулю.

Пока комментариев нет, будь первым!


Как гласит недавний отчет Stack Overflow (а также отчеты GitHub), самый популярный язык программирования в мире на данный момент — JavaScript. Отчасти язык популярен своей небывалой распространенностью в браузерах, отчастью он обязан своей популярностью и серверной платформе NodeJS, позволяющей писать программы, выполняемые не только в браузерах клиентских машин, но и на серверах.

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

Как правильно перевозить грузы

Такая модульность стала своего рода традицией экосистемы NPM. Модули стали писать по случаю и без. На каждый чих — свой модуль, и вряд ли еще остались слова английского (и не только) языка, не занятые под название модуля с модной припиской “JS” на конце.

И вот эта страсть к высокодробной модульности и вышла NPM и его обитателям боком. На неделе разгорелся небольшой скандал на почве обрушения части NPM из-за смешного инцидента. Некий Азер Кочулу (Azer Koçulu), автор более 250 модулей к NodeJS, являвшийся владельцем модуля под названием kik, получил письмо от сотрудников мессенджера Kik, попросившего его уступить им «кошерное» название в NPM. Азер отказался пойти навстречу, и сотрудники мессенджера Kik отправили аналогичное письмо руководству платформы NPM. NPM решила отнять у Азера красивое имя для модуля и отдать его мессенджеру Kik. Тут Азер, по понятным причинам, негодуя от такой несправедливости, выпилил весь свой зоопарк модулей с NPM (напомню, это более 250 наименований)...

И тут главный прикол всего цирка: оказалось, что от его модулей зависит куча крупных проектов, в числе которых такие монстры, как Фейсбуковский React, JavaScript-транскомпилятор Babel и, по цепочке, огромное количество других модулей и программ. А так как Азер отозвал свои поделия, то вся эта инфраструктура рухнула как карточный домик. И что еще более смешно в этой непростой ситуации, модуль под названием leftpad, от которого зависило множество других крупных проектов, состоял из… 11 строчек кода! И ладно бы в этих 11 строках кода были бы заключена вселенская мудрость или хотя бы результат большой научной работы, сконцентрированный в лаконичную формулировку (E = mc²). Нет, модуль делал довольно тупую и банальную вещь — добавлял нули или пробелы в левой части заданной строки или числа!

module.exports = leftpad;
function leftpad (str, len, ch) {
  str = String(str);
  var i = -1;
  if (!ch && ch !== 0) ch = ' ';
  len = len - str.length;
  while (++i < len) {
    str = ch + str;
  }
  return str;
}

То есть, сложно представить себе более банальную вещь, чем эти 11 строчек кода (две из которых — фигурные скобки). В Python, например, эта функция вообще встроена в язык и делается простейшим форматированием строки:

'{0:06d}'.format(6)

То есть, крупнейшие и сложнейшие проекты включили в себя модуль из десятка строк тупого кода, который можно было бы оформить буквально за две минуты самостоятельно (без создания лишних зависимостей). И в среде NPM такое на каждом шагу — это часть культуры! Прекрасным примером этому может послужить небольшое исследование Дэвида Хейни (David Haney), который прошерстил NPM на предмет наличия подобных «модулей».

Трюк с байками

Например, оказалось, что есть такой замечательный модуль, как isArray. Этот модуль скачало 880 000 человек за один день, кроме того, он был загружен 18 миллионов раз только в одном феврале этого года! От этого модуля напрямую зависят 72 пакета в NPM. И что же это за чудесный модуль такой?

return toString.call(arr) == '[object Array]';

А модуль этот состоит из одной. ОДНОЙ! Строчки дурацкого кода, приведенного выше. И призван проверять — не массив ли перед нами…

Есть еще один чудесный модуль с говорящим названием is-positive-integer (GitHub), до смешного банальный — он проверяет, положительное ли целое число ему передано. Состоит из целых четырех строк кода (!!!) и (внимание!) требует три зависимости для своей работы! То есть требовал, недавно автор «отрефакторил» свой код, и теперь его важнейший модуль не требует зависимостей вообще (вот он — подвиг программиста)!

Индийский мотоциклетный парад

А вот еще один пример, приведенный в комментариях на Хабре — очередной модуль «для проверки типа» — isnumber. Одна тупая строчка:

return !isNaN(parseFloat(n)) && isFinite(n);

И вот такая вот развесистая система приводит к тому, что какой-нибудь Babel включает в себя 41 000 файлов (и это свежеустановленный пакет!), а также генерирует чистый шаблонный проект (jspm/npm) с… более чем 28 000 файлов! Эта, вроде бы неплохая изначально идея компактных модулей, была доведена до полнейшего, абсолютного, феерического абсурда. Мало того, что с каждой такой дурацкой зависимостью вы добавляете еще одну точку отказа в своем коде (которую нельзя потом оперативно отладить), так еще и автоматически полагаетесь на качество кода горе-программистов (типа упомянутого выше, что проверял положительность целого числа тремя зависимостями).

Индийский мотоциклетный парад

P.S. Кстати, теперь уже печально известный модуль leftpad, удаленный Азером, в итоге восстановили без его одобрения, в качестве экстренной меры, чтобы не «поломать систему».


В разделах программирование и языковое
Андрей Баксаляр  :: 10 мар 2016, в 23:09

Работая с греческим алфавитом в Unicode, в Python 3.4.3, наткнулся на странный баг (по всей видимости, здесь косяк как Пайтона, так и таблиц Юникода). Если у вас интерпретатор версии 3.4-3.5, то проблема легко воспроизводится следующим образом:

'ΰ'.upper().lower() == 'ΰ'

Интерпретатор неожиданно выдаст вам False. Несмотря на то, что по логике вещей ΰ == ΰ. После преобразований регистра из-за проблемы с правилами меппинга Unicode, Пайтон подменяет ΰ на ΰ:

'ΰ'.upper().lower().encode('utf-8')
b'\xcf\x85\xcc\x88\xcc\x81'
'ΰ'.encode('utf-8')
b'\xce\xb0'

Как видно, исходный символ и символ, возвращаемый lower() — разные, второй возвращается с другим диакритическим знаком, что даже визуально заметно в редакторе (да и на странице видно невооруженным глазом), хотя так быть точно не должно.

ΰu → ΰu

При дальнейшем гуглении оказалось, что о данном глюке уже было сообщено. И сообщение пайтоновского багтрекера даже успели закрыть с формулировкой «исправлено» более четырех лет назад, перед выпуском Python 3.3, только вот баг остался даже в свежей версии Python 3.5.1 (а также 3.4.3), а вот во второй ветке (проверено на Python 2.7.6 от 22 июня 2015) он исправлен.

Воспроизведение бага в Python 2.7.6, 3.4.3 и 3.5.1

Кроме того, баг оказался более обширным, чем думалось изначально. В конце статьи (под катом) вы найдете таблицу символов-оборотней, меняющихся с двойным изменением регистра.

Например…

(
unicodedata.name('Ω'.upper().lower()),
unicodedata.name('Ω')
)

... неожиданно возвращает:

('GREEK SMALL LETTER OMEGA', 'OHM SIGN')

Написал сообщение в тикет, будем ждать ответа. Также попробовал обновить Пайтон до самой последней версии, однако это не помогло.

P.S. Интересно, что данная проблема затрагивает и NodeJS версий 5.6.0 (стабильная) и 5.8.0 (самая свежая):

Воспроизведение бага в NodeJS 5.6

Воспроизведение бага в NodeJS 5.8

Однако в консоли браузера (Firefox 44.0.2) проблема уже не воспроизводится:

Воспроизведение бага в JavaScript внутри браузера Firefox 44.0.2

P.P.S. В качестве костыльного решения в Пайтоне предлагается использовать такой подход:

unicodedata.normalize('NFC', 'ΰ'.upper().lower()) == 'ΰ'
True
Исходник.upper().lower()Снова .upper()
µ (0xb5)Μ (0x39c)μ (0x3bc)Μ (0x39c)
ß (0xdf)SS (0x5353)ss (0x7373)SS (0x5353)
İ (0x130) (0x69307) (0x49307) (0x69307)
ı (0x131)I (0x49)i (0x69)I (0x49)
ʼn (0x149)ʼN (0x2bc4e)ʼn (0x2bc6e)ʼN (0x2bc4e)
ſ (0x17f)S (0x53)s (0x73)S (0x53)
ǰ (0x1f0) (0x4a30c) (0x6a30c) (0x4a30c)
ͅ (0x345)Ι (0x399)ι (0x3b9)Ι (0x399)
ΐ (0x390)Ϊ́ (0x399308301)ΐ (0x3b9308301)Ϊ́ (0x399308301)
ΰ (0x3b0)Ϋ́ (0x3a5308301)ΰ (0x3c5308301)Ϋ́ (0x3a5308301)
ς (0x3c2)Σ (0x3a3)σ (0x3c3)Σ (0x3a3)
ϐ (0x3d0)Β (0x392)β (0x3b2)Β (0x392)
ϑ (0x3d1)Θ (0x398)θ (0x3b8)Θ (0x398)
ϕ (0x3d5)Φ (0x3a6)φ (0x3c6)Φ (0x3a6)
ϖ (0x3d6)Π (0x3a0)π (0x3c0)Π (0x3a0)
ϰ (0x3f0)Κ (0x39a)κ (0x3ba)Κ (0x39a)
ϱ (0x3f1)Ρ (0x3a1)ρ (0x3c1)Ρ (0x3a1)
ϴ (0x3f4)θ (0x3b8)Θ (0x398)θ (0x3b8)
ϵ (0x3f5)Ε (0x395)ε (0x3b5)Ε (0x395)
և (0x587)ԵՒ (0x535552)եւ (0x565582)ԵՒ (0x535552)
(0x1e96) (0x48331) (0x68331) (0x48331)
(0x1e97) (0x54308) (0x74308) (0x54308)
(0x1e98) (0x5730a) (0x7730a) (0x5730a)
(0x1e99) (0x5930a) (0x7930a) (0x5930a)
(0x1e9a) (0x412be) (0x612be) (0x412be)
(0x1e9b) (0x1e60) (0x1e61) (0x1e60)
(0x1e9e)ß (0xdf)SS (0x5353)ss (0x7373)
(0x1f50)Υ̓ (0x3a5313)ὐ (0x3c5313)Υ̓ (0x3a5313)
(0x1f52)Υ̓̀ (0x3a5313300)ὒ (0x3c5313300)Υ̓̀ (0x3a5313300)
(0x1f54)Υ̓́ (0x3a5313301)ὔ (0x3c5313301)Υ̓́ (0x3a5313301)
(0x1f56)Υ̓͂ (0x3a5313342)ὖ (0x3c5313342)Υ̓͂ (0x3a5313342)
(0x1f80)ἈΙ (0x1f08399)ἀι (0x1f003b9)ἈΙ (0x1f08399)
(0x1f81)ἉΙ (0x1f09399)ἁι (0x1f013b9)ἉΙ (0x1f09399)
(0x1f82)ἊΙ (0x1f0a399)ἂι (0x1f023b9)ἊΙ (0x1f0a399)
(0x1f83)ἋΙ (0x1f0b399)ἃι (0x1f033b9)ἋΙ (0x1f0b399)
(0x1f84)ἌΙ (0x1f0c399)ἄι (0x1f043b9)ἌΙ (0x1f0c399)
(0x1f85)ἍΙ (0x1f0d399)ἅι (0x1f053b9)ἍΙ (0x1f0d399)
(0x1f86)ἎΙ (0x1f0e399)ἆι (0x1f063b9)ἎΙ (0x1f0e399)
(0x1f87)ἏΙ (0x1f0f399)ἇι (0x1f073b9)ἏΙ (0x1f0f399)
(0x1f90)ἨΙ (0x1f28399)ἠι (0x1f203b9)ἨΙ (0x1f28399)
(0x1f91)ἩΙ (0x1f29399)ἡι (0x1f213b9)ἩΙ (0x1f29399)
(0x1f92)ἪΙ (0x1f2a399)ἢι (0x1f223b9)ἪΙ (0x1f2a399)
(0x1f93)ἫΙ (0x1f2b399)ἣι (0x1f233b9)ἫΙ (0x1f2b399)
(0x1f94)ἬΙ (0x1f2c399)ἤι (0x1f243b9)ἬΙ (0x1f2c399)
(0x1f95)ἭΙ (0x1f2d399)ἥι (0x1f253b9)ἭΙ (0x1f2d399)
(0x1f96)ἮΙ (0x1f2e399)ἦι (0x1f263b9)ἮΙ (0x1f2e399)
(0x1f97)ἯΙ (0x1f2f399)ἧι (0x1f273b9)ἯΙ (0x1f2f399)
(0x1fa0)ὨΙ (0x1f68399)ὠι (0x1f603b9)ὨΙ (0x1f68399)
(0x1fa1)ὩΙ (0x1f69399)ὡι (0x1f613b9)ὩΙ (0x1f69399)
(0x1fa2)ὪΙ (0x1f6a399)ὢι (0x1f623b9)ὪΙ (0x1f6a399)
(0x1fa3)ὫΙ (0x1f6b399)ὣι (0x1f633b9)ὫΙ (0x1f6b399)
(0x1fa4)ὬΙ (0x1f6c399)ὤι (0x1f643b9)ὬΙ (0x1f6c399)
(0x1fa5)ὭΙ (0x1f6d399)ὥι (0x1f653b9)ὭΙ (0x1f6d399)
(0x1fa6)ὮΙ (0x1f6e399)ὦι (0x1f663b9)ὮΙ (0x1f6e399)
(0x1fa7)ὯΙ (0x1f6f399)ὧι (0x1f673b9)ὯΙ (0x1f6f399)
(0x1fb2)ᾺΙ (0x1fba399)ὰι (0x1f703b9)ᾺΙ (0x1fba399)
(0x1fb3)ΑΙ (0x391399)αι (0x3b13b9)ΑΙ (0x391399)
(0x1fb4)ΆΙ (0x386399)άι (0x3ac3b9)ΆΙ (0x386399)
(0x1fb6)Α͂ (0x391342)ᾶ (0x3b1342)Α͂ (0x391342)
(0x1fb7)Α͂Ι (0x391342399)ᾶι (0x3b13423b9)Α͂Ι (0x391342399)
(0x1fbe)Ι (0x399)ι (0x3b9)Ι (0x399)
(0x1fc2)ῊΙ (0x1fca399)ὴι (0x1f743b9)ῊΙ (0x1fca399)
(0x1fc3)ΗΙ (0x397399)ηι (0x3b73b9)ΗΙ (0x397399)
(0x1fc4)ΉΙ (0x389399)ήι (0x3ae3b9)ΉΙ (0x389399)
(0x1fc6)Η͂ (0x397342)ῆ (0x3b7342)Η͂ (0x397342)
(0x1fc7)Η͂Ι (0x397342399)ῆι (0x3b73423b9)Η͂Ι (0x397342399)
(0x1fd2)Ϊ̀ (0x399308300)ῒ (0x3b9308300)Ϊ̀ (0x399308300)
(0x1fd3)Ϊ́ (0x399308301)ΐ (0x3b9308301)Ϊ́ (0x399308301)
(0x1fd6)Ι͂ (0x399342)ῖ (0x3b9342)Ι͂ (0x399342)
(0x1fd7)Ϊ͂ (0x399308342)ῗ (0x3b9308342)Ϊ͂ (0x399308342)
(0x1fe2)Ϋ̀ (0x3a5308300)ῢ (0x3c5308300)Ϋ̀ (0x3a5308300)
(0x1fe3)Ϋ́ (0x3a5308301)ΰ (0x3c5308301)Ϋ́ (0x3a5308301)
(0x1fe4)Ρ̓ (0x3a1313)ῤ (0x3c1313)Ρ̓ (0x3a1313)
(0x1fe6)Υ͂ (0x3a5342)ῦ (0x3c5342)Υ͂ (0x3a5342)
(0x1fe7)Ϋ͂ (0x3a5308342)ῧ (0x3c5308342)Ϋ͂ (0x3a5308342)
(0x1ff2)ῺΙ (0x1ffa399)ὼι (0x1f7c3b9)ῺΙ (0x1ffa399)
(0x1ff3)ΩΙ (0x3a9399)ωι (0x3c93b9)ΩΙ (0x3a9399)
(0x1ff4)ΏΙ (0x38f399)ώι (0x3ce3b9)ΏΙ (0x38f399)
(0x1ff6)Ω͂ (0x3a9342)ῶ (0x3c9342)Ω͂ (0x3a9342)
(0x1ff7)Ω͂Ι (0x3a9342399)ῶι (0x3c93423b9)Ω͂Ι (0x3a9342399)
(0x2126)ω (0x3c9)Ω (0x3a9)ω (0x3c9)
(0x212a)k (0x6b)K (0x4b)k (0x6b)
(0x212b)å (0xe5)Å (0xc5)å (0xe5)
(0xfb00)FF (0x4646)ff (0x6666)FF (0x4646)
(0xfb01)FI (0x4649)fi (0x6669)FI (0x4649)
(0xfb02)FL (0x464c)fl (0x666c)FL (0x464c)
(0xfb03)FFI (0x464649)ffi (0x666669)FFI (0x464649)
(0xfb04)FFL (0x46464c)ffl (0x66666c)FFL (0x46464c)
(0xfb05)ST (0x5354)st (0x7374)ST (0x5354)
(0xfb06)ST (0x5354)st (0x7374)ST (0x5354)
(0xfb13)ՄՆ (0x544546)մն (0x574576)ՄՆ (0x544546)
(0xfb14)ՄԵ (0x544535)մե (0x574565)ՄԵ (0x544535)
(0xfb15)ՄԻ (0x54453b)մի (0x57456b)ՄԻ (0x54453b)
(0xfb16)ՎՆ (0x54e546)վն (0x57e576)ՎՆ (0x54e546)
(0xfb17)ՄԽ (0x54453d)մխ (0x57456d)ՄԽ (0x54453d)

Пока комментариев нет, будь первым!


Случается иногда такая необходимость, выдернуть все нужные ссылки со страницы в браузере, а ссылок тысяча и вручную это делать, мягко говоря, нерационально. Задачу легко автоматизировать, используя возможности JavaScript и метода map. Как это работает:

  1. Жмем F12, чтобы увидеть консоль разработчика в современном браузере (Chrome / Firefox). Или запускаем эту самую консоль другим методом, который нравится лично вам.

  2. Затем пишем в консоли следующую команду:

<Array.prototype.slice.call(document.querySelectorAll('a')).map(function (el) { return el.href })

Если на странице подключен JQuery, то команда упрощается до:

$.map($('a'), function (el) { return el.href })

Жирным выделено место, куда мы вставляем необходимый селектор. Например, в моем случае с выдиранием большого количества ссылок на ютубе, селектор был таким: .yt-lockup-title > a (выбор всех непосредственных дочерних элементов h3 с классом yt-lockup-title). Вот что получается в итоге:

Получение всех ссылок со страницы

Для более удобного вывода можно дампить все прямо в консоль, а не возвращать элементы массивом:

Array.prototype.slice.call(document.querySelectorAll('.yt-lockup-title > a')).map(function (el) { console.log(el.href) } )

Потом удобно закинуть этот список в текстовый файл и скормить какому-нибудь консольному youtube-dl командой:

youtube-dl --batch-file='links.txt'

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


В разделах интернет, технологии и будущее
Андрей Баксаляр  :: 4 сен 2014, в 19:26

Потихоньку вникаю сейчас в web-программирование — на самом деле, по ощущениям, офигенно интересная область с огромным потенциалом и безграничными возможностями. Не последнюю лепту в это вносят мощные мультимедийные и, в частности, графические возможности и простота манипуляций с элементами документа. Особенно это заметно на фоне новых web-технологий типа CSS3, HTML5 и прочих WebGL.

Демонстрация 3D в HTML5

Кадр из демонстрации «HTML5logo»

Интересно, что современные инструменты и библиотеки предоставляют богатые возможности при довольно низкой «входной цене» в плане знаний и объема трудозатрат на реализацию. Большой прогресс в скорости обработки скриптов, элементов HTML и их свойств, а также сопутствующее упрощение кода (ну и, конечно, совершенствование технологий серверной части) — все это становится ключом к быстрому развитию. Как только начинаешь изучать вопрос, открывается видение большого потенциала, которым сейчас пользуются процентов на 20, если не того меньше.

Подавляющее большинство современных web-приложений в интернете — это на самом деле морально устаревший софт, который остается на плаву по ряду причин. Здесь и обязательная для крупных проектов кроссбраузерная совместимость, являющаяся фактором, оттягивающим прогресс (да-да, опять Internet Explorer), и тянущее назад наследство из уже сложившихся традиций, а также существующих библиотек и приложений (всякие мутные, но популярные CMS-ки и прочие монструозные «движки», которые никто просто так переписывать, переделывать и модернизировать не будет). Другими словами, в вебе уже произошла технологическая революция, но большинство ее не заметили, или попросту не обратили внимания. Теперь она плавно и ненавязчиво, все же, внедряется сетевой быт.

О чем я говорю. Покажу на примерах. Вот так может, например, выглядеть современный сайт:

Отличная презентация польской студии Bright Media на чистом CSS и JavaScript (+ графическая библиотека GreenSock):

Демонстрация web-технологий от Bright Media

Еще несколько интересных примеров...

Еще одна презентация, насыщенная анимацией (тот же GreenSock):

GreenSock — Soleilnoir.net

Небольшая демка библиотеки Velicity.js:

Демонстрация движка Velocity

Плюс, небольшая демонстрация возможностей CSS- и JS-анимации на примере реального проекта:

Сodeandtheory.com

Графическая технология raytracing (трассировка лучей), которая будет во всех играх будущего (пока не хватает вычислительных мощностей) — прямо онлайн, правда, по понятным причинам, не в режиме реального времени пока:

Демонстрации насыщенной графики и анимации HTML5 — developer.mozilla.org

Трехмерная коробка с бумажным «пастбищем» средствами чистого CSS и JS:

Трехмерная коробка в новом HTML5

Ну и, конечно, «интерактивный сон» — впечатляющий демо-проект популяризации WebGL, о котором грех не упомянуть — 3 Dreams of Black:

3 Dreams of Black

И так далее и тому подобное. Так что будущее персональных вычислений для работы, учебы и развлечений, определенно, за вебом нового поколения. Кто бы сомневался…

А ведь все это начиналось примерно с такого уродства:

Веб-страница из прошлого

Пока комментариев нет, будь первым!

Войти через...


Это даст читателю возможность голоса, комментария, создания закладки, и даже написания поста, не говоря о множестве других мелких ништяков.

Соациализируемся


Также найти меня можно в других злачных местах:

Все еще использую электронную почту:
andreybaksalyar@ya.ru