[{"data":1,"prerenderedAt":1416},["ShallowReactive",2],{"$fzFWevqvbgS2zhOh55iVE3WJlnF98KhuhM5v1PrOI8oc":3,"$fMMUdSFktwQFqMVGPrTtt3EC5yheBp7PzwIqznamFcMo":135,"$fc0LoAJgqXDLbKKd2JS_NpM4SuzBK8EycUXINSg09CKU":138,"$fM3ea55k6lKMPOTM84llDB26VSQDVVbxiQuSBFQw9P_c":143,"$f1Prj1xEczHja_-L7FyIGgRHd5_cSWHo7r6AE5aheAik":488,"$fI5fDmvm-5tr9wcH0eHaKZa1j3y_FQIQaHHPqbZxAHJE":710,"mdc-jfvix8-key":730,"mdc-silpyw-key":742,"mdc--j8l7hd-key":750,"mdc-y5b84b-key":776,"mdc--en0i1p-key":784,"mdc--5ctk81-key":801,"mdc--55toj4-key":818,"mdc--s3hxle-key":833,"mdc--sly51i-key":886,"mdc--8dvt1t-key":903,"mdc-i4pxv7-key":934,"mdc-1s2yz4-key":977,"mdc-qq353s-key":1021,"mdc--10je6g-key":1056,"mdc-he6hzl-key":1073,"mdc--pz1wiq-key":1082,"mdc--dch88r-key":1113,"mdc--iev8bk-key":1146,"mdc-npkhli-key":1192,"mdc-u5a7nk-key":1200,"mdc-kaay34-key":1246,"mdc--tgkaxo-key":1380,"mdc--vnr7y0-key":1408},{"content":4,"quizQuestionContent":106,"type":125,"pageMeta":126},[5,9,13,16,20,24,28,31,35,38,41,45,48,52,55,58,62,65,69,72,76,79,83,86,89,93,96,100,103],{"id":6,"value":7,"isTypeH1":8},"1922","Почему опасно менять прототипы базовых типов в JS",true,{"id":10,"value":11,"anchor":12,"isTypeH2":8},"4429","Теория: прототипы и цепочка","theory-prototypes-and-chain",{"id":14,"value":15,"isTypeParagraph":8},"10192","В JavaScript у объектов есть внутренняя ссылка на прототип (часто объясняется как “цепочка прототипов”), по которой движок ищет свойства и методы, если их нет в самом объекте. У массивов методы лежат в `Array.prototype`, у строк — в `String.prototype`, и почти все объекты в итоге наследуют от `Object.prototype`.\n\nМеханизм поиска свойства упрощённо выглядит так: сначала проверяются собственные свойства объекта, затем свойства прототипа, затем прототипа прототипа и так далее, пока цепочка не закончится.\n\nСхема поиска свойства:\n\n```\nObject instance\n  |\n  v\n(собственные свойства)\n  |\n  v\nSomeType.prototype\n  |\n  v\nObject.prototype\n  |\n  v\nnull\n```",{"id":17,"description":18,"titleAlert":19,"isTypeAlertInfo":8},"663","Запись в `SomeType.prototype` меняет “общую базу методов” для всех экземпляров этого типа, включая уже созданные.",null,{"id":21,"value":22,"anchor":23,"isTypeH2":8},"4430","Почему это опасно","why-it-is-dangerous",{"id":25,"value":26,"anchor":27,"isTypeH3":8},"4444","Глобальные побочные эффекты","global-side-effects",{"id":29,"value":30,"isTypeParagraph":8},"10193","Добавление, например, `Array.prototype.myMethod` влияет на все массивы в приложении и во всех подключённых зависимостях. Из-за этого ошибка может проявиться в другом месте: код меняется в одном файле, а ломается логика в библиотеке, которая никогда не ожидала появления нового свойства с таким именем.\n\nПример “глобальности”:\n\n```\n/ Изменение прототипа массива (опасная практика)\nArray.prototype.sum = function () {\n  return this.reduce((a, b) => a + b, 0);\n};\n\nconsole.log([1, 2, 3].sum()); // 6\n\n// Важно: метод появился у всех массивов, включая те, что создаются в стороннем коде\n```",{"id":32,"value":33,"anchor":34,"isTypeH3":8},"4445","Конфликты имён (с библиотеками и будущим стандартом)","name-collisions",{"id":36,"value":37,"isTypeParagraph":8},"10194","Если добавляется метод с популярным именем, то существует риск, что:\n- библиотека уже добавляет метод с таким же именем, но с другой логикой;\n- другая часть проекта рассчитывает, что такого метода не существует;\n- среда выполнения позже добавит стандартный метод с таким именем, но с иным контрактом.\n\nПример конфликта имён (идея упрощена):\n\n```\n// Приложение добавляет метод с коротким именем\nString.prototype.format = function () {\n  return \"локальная логика форматирования\";\n};\n\n// Где-то в зависимости ожидается другое поведение format()\n// или в будущем стандарт добавит одноимённый метод с другой семантикой\nconsole.log(\"x\".format());\n```",{"id":39,"description":40,"titleAlert":19,"isTypeAlertWarning":8},"724","Конфликт имён особенно опасен тем, что не всегда приводит к явной ошибке: код может “просто работать иначе”, незаметно и неправильно.",{"id":42,"value":43,"anchor":44,"isTypeH3":8},"4446","Неожиданное перечисление свойств","unexpected-enumeration",{"id":46,"value":47,"isTypeParagraph":8},"10195","Некоторые конструкции перебирают свойства, включая унаследованные (например, `for...in`). Если в прототип добавлено перечислимое свойство, оно может внезапно появиться в переборе и сломать алгоритм, который ожидает только индексы массива или только реальные поля объекта.\n\nПример ошибки при перечислении:\n\n```\n// Добавление перечислимого свойства в прототип (опасно)\nArray.prototype.extra = 123;\n\nconst arr = [10, 20];\n\nfor (const k in arr) {\n  // Ожидаются \"0\" и \"1\", но также может появиться \"extra\"\n  console.log(k);\n}\n```\n\nДаже если метод добавляется через `Object.defineProperty(..., { enumerable: false })`, остаются другие риски: глобальное изменение поведения, конфликты имён, влияние на проверки наличия свойства и на совместимость.",{"id":49,"value":50,"anchor":51,"isTypeH3":8},"4447","Риски безопасности: prototype pollution","prototype-pollution",{"id":53,"value":54,"isTypeParagraph":8},"10196","Prototype pollution — ситуация, когда из-за обработки непроверенных данных в прототипы (часто в `Object.prototype`) попадают новые свойства. После этого эти свойства становятся “видимыми” для многих объектов и способны повлиять на проверки, условия и настройки по всему приложению.\n\nТипичный источник проблемы — “слияние” объектов, пришедших извне (например, из JSON), без фильтрации опасных ключей.\n\nПример, демонстрирующий идею (упрощённо):\n\n```\nfunction merge(target, source) {\n  for (const key in source) {\n    target[key] = source[key];\n  }\n  return target;\n}\n\n// Непроверенный ввод\nconst payload = JSON.parse('{\"__proto__\":{\"isAdmin\":true}}');\n\nconst user = {};\nmerge(user, payload);\n\n// Опасный эффект: свойство может начать \"как бы существовать\" у многих объектов\nconst obj = {};\nconsole.log(obj.isAdmin); // потенциально true в уязвимых сценариях\n```",{"id":56,"description":57,"titleAlert":19,"isTypeAlertInfo":8},"664","Даже “маленькое” изменение прототипов может стать причиной обхода проверок доступа, если где-то в коде используется логика наподобие `if (obj.isAdmin) ...` без строгой валидации источника этого значения.",{"id":59,"value":60,"anchor":61,"isTypeH2":8},"4431","Как правильно решать задачу","how-to-solve-correctly",{"id":63,"value":64,"isTypeParagraph":8},"10197","Надёжнее не менять встроенные прототипы, а выносить функциональность в обычные функции, модули или классы-обёртки. Такой код проще тестировать, проще читать и невозможно “случайно” навязать всем объектам в программе.\n",{"id":66,"value":67,"anchor":68,"isTypeH3":8},"4448","Утилитные функции","utility-functions",{"id":70,"value":71,"isTypeParagraph":8},"10198","Пример замены `Array.prototype.unique` на обычную функцию:\n\n```\nfunction unique(arr) {\n  return Array.from(new Set(arr));\n}\n\nconsole.log(unique([1, 1, 2])); // [1, 2]\n```\n\nПлюсы: отсутствуют глобальные побочные эффекты, проще типизировать, проще переиспользовать, легче сопровождать.",{"id":73,"value":74,"anchor":75,"isTypeH3":8},"4449","Безопасные структуры вместо “словаря на Object”","safer-structures-than-object",{"id":77,"value":78,"isTypeParagraph":8},"10199","Если необходима структура “ключ → значение”, часто безопаснее `Map`, потому что он не использует `Object.prototype` как часть механики доступа к ключам.\n\n```\nconst m = new Map();\nm.set(\"__proto__\", \"ok\");\nconsole.log(m.get(\"__proto__\")); // \"ok\"\n```",{"id":80,"value":81,"anchor":82,"isTypeH3":8},"4450","Полифилы только по строгой необходимости","polyfills-only",{"id":84,"value":85,"isTypeParagraph":8},"10200","Единственный относительно оправданный случай изменения прототипа — полифил стандартного метода для старого окружения, когда:\n- метод отсутствует;\n- добавление точно повторяет контракт стандарта;\n- свойство делается неперечислимым;\n- решение документировано и контролируется (обычно в одном месте проекта).\n\nПример “аккуратного” добавления (упрощённая форма):\n\n```\nif (!Array.prototype.myPolyfilledMethod) {\n  Object.defineProperty(Array.prototype, \"myPolyfilledMethod\", {\n    value: function () {\n      return \"реализация\";\n    },\n    enumerable: false,\n    writable: true,\n    configurable: true\n  });\n}\n```",{"id":87,"description":88,"titleAlert":19,"isTypeAlertInfo":8},"665","Полифил, который ведёт себя “почти как стандарт”, часто хуже отсутствия метода: создаётся ложное ощущение совместимости.",{"id":90,"value":91,"anchor":92,"isTypeH3":8},"4451","Защита при слиянии объектов","safe-merge",{"id":94,"value":95,"isTypeParagraph":8},"10201","При обработке внешнего ввода следует исключать опасные ключи (`__proto__`, `constructor`, `prototype`) и по возможности создавать объекты без прототипа для роли “чистого словаря”.\n\nПример:\n\n```\nfunction safeAssign(target, source) {\n  for (const key of Object.keys(source)) {\n    if (key === \"__proto__\" || key === \"constructor\" || key === \"prototype\") continue;\n    target[key] = source[key];\n  }\n  return target;\n}\n\nconst dict = Object.create(null);\nsafeAssign(dict, JSON.parse('{\"a\":1,\"__proto__\":{\"polluted\":true}}'));\n\nconsole.log(dict.a); // 1\n```",{"id":97,"value":98,"anchor":99,"isTypeH2":8},"4432","Таблица рисков и замен","risk-table-and-alternatives",{"id":101,"value":102,"isTypeParagraph":8},"10202","| Риск | Как проявляется | Безопасная альтернатива |\n|---|---|---|\n| Глобальные изменения поведения | “Ломается” код в другом модуле или зависимости | Утилитные функции, отдельные модули |\n| Конфликты имён | Одинаковое имя метода, разный контракт | Явный импорт функции, неймспейсы |\n| Неожиданное перечисление | Лишние ключи в `for...in`, некорректные проверки | `Object.keys()`, строгая проверка собственных свойств |\n| Prototype pollution | Внешний ввод влияет на прототипы и проверки | Фильтрация ключей, `Object.create(null)`, `Map` |",{"id":104,"value":105,"isTypeParagraph":8},"10203","В итоге: опасность записи прямо в прототипы базовых типов (например, `Object.prototype`, `Array.prototype`, `String.prototype`) заключается в том, что меняется поведение сразу у всех значений данного типа во всей программе, включая сторонние библиотеки и будущие обновления среды. Это приводит к труднообнаружимым ошибкам, конфликтам имён, проблемам совместимости и иногда к уязвимостям, связанным с загрязнением прототипов (prototype pollution).",{"id":107,"options":108,"hint":122,"solution":123,"description":124},"1156",[109,112,116,119],{"id":110,"label":111,"isCorrect":8},"4768","Опасность связана с тем, что добавленные свойства и методы становятся общими для всех экземпляров типа, поэтому сторонний код может начать работать иначе, а перечисление свойств и проверки наличия ключей способны давать неожиданные результаты. Дополнительно возникают конфликты имён с библиотеками и будущими стандартными методами, поэтому практики качества кода часто запрещают такие изменения.",{"id":113,"label":114,"isCorrect":115},"4769","Опасность заключается в том, что строгий режим запрещает любые изменения прототипов базовых типов, поэтому приложение перестаёт запускаться в современных браузерах. В результате попытка добавить метод в `Array.prototype` или `Object.prototype` приводит к синтаксической ошибке на этапе разбора кода, и выполнение становится невозможным.",false,{"id":117,"label":118,"isCorrect":115},"4770","Опасность состоит главным образом в увеличении размера сборки: любые изменения прототипов автоматически дублируются в каждом модуле, поэтому сборщик вставляет одну и ту же реализацию много раз. Это увеличивает итоговый размер JavaScript-файлов и ухудшает скорость загрузки страницы, даже если добавленный метод фактически не используется.",{"id":120,"label":121,"isCorrect":115},"4771","Опасность сводится к потере доступа к приватным полям классов: при добавлении методов в прототипы встроенных типов приватные поля (`#field`) начинают конфликтовать с цепочкой прототипов. Это вызывает массовые ошибки обращения к приватным данным и делает классы непригодными для применения в реальных проектах.","Для объяснения достаточно представить прототип как “общий источник методов” для всех значений типа и помнить: запись в `*.prototype` меняет поведение всей программы, поэтому ошибка становится глобальной, а при обработке внешних данных возможны сценарии загрязнения прототипов.","**Правильный ответ: 1** - Опасность связана с тем, что добавленные свойства и методы становятся общими для всех экземпляров типа, поэтому сторонний код может начать работать иначе, а перечисление свойств и проверки наличия ключей способны давать неожиданные результаты. Дополнительно возникают конфликты имён с библиотеками и будущими стандартными методами, поэтому практики качества кода часто запрещают такие изменения.","Почему опасно писать прямо в прототипы базовых типов?","quizQuestion",{"title":124,"description":127,"ogTitle":7,"ogDescription":127,"ogImageUrl":128,"canonical":19,"ogLocale":129,"ogSiteName":130,"ogImageType":131,"ogImageWidth":132,"ogImageHeight":133,"ogType":134,"ogUrl":19},"Разбор рисков изменения Object/Array/String.prototype: баги, конфликты, перечисление свойств, prototype pollution и безопасные альтернативы","/og-image.png","ru_RU","goodwebjob.ru","image_jpeg","1200","630","article",{"siteName":136,"siteUrl":137},"GOOD WEB JOB!","https://goodwebjob.ru",[139],{"label":140,"slug":141,"to":142},"Подготовка к тех.интервью","technical-interview","/technical-interview/where-to-begin",{"navigationList":144,"navigationSublist":152},[145,148],{"path":142,"isActive":115,"name":146,"icon":147,"isNavbarMobileDisabled":8},"С чего начать?","material-symbols:visibility-outline-rounded",{"path":149,"isActive":8,"name":150,"icon":151,"isNavbarMobileDisabled":115},"/technical-interview/tasks","Сборник задач","material-symbols:task-outline",[153,162,189,201,207,347,371,380,386,449,470,476],{"title":154,"list":155,"isOpened":115},"Bash",[156,159],{"name":157,"path":158,"isActive":115},"Дан фрагмент bash-скрипта: cd ~; mkdir foo... Что в нем происходит?","/technical-interview/tasks/here-is-a-fragment-of-a-bash-script-cd-mkdir-foo-what-is-happening-in-this-script",{"name":160,"path":161,"isActive":115},"Дан фрагмент bash-скрипта: target=$(ps -Af | grep $1 | head -n 1)...","/technical-interview/tasks/here-is-a-fragment-of-a-bash-script-target-ps-af-grep-1-head-n-1",{"title":163,"list":164,"isOpened":115},"CSS",[165,168,171,174,177,180,183,186],{"name":166,"path":167,"isActive":115},"Дан HTML-код. Какой будет цвет у текста «Some dummy text»?","/technical-interview/tasks/the-html-code-is-given-what-will-be-the-color-of-the-some-dummy-text",{"name":169,"path":170,"isActive":115},"Есть шаблон HTML и CSS кода. Какой будет цвет у текста «Таким образом, постоянное»?","/technical-interview/tasks/there-is-a-template-for-html-and-css-code-what-color-will-the-text-thus-constant-have",{"name":172,"path":173,"isActive":115},"Есть шаблон вложенного HTML кода. Какой будет цвет у текста «One more dummy text»?","/technical-interview/tasks/there-is-a-template-for-embedded-html-code-what-will-be-the-color-of-the-one-more-dummy-text",{"name":175,"path":176,"isActive":115},"Есть шаблон вложенного HTML кода. Будет ли display:block у body влиять на span?","/technical-interview/tasks/there-is-a-template-for-embedded-html-code-will-there-be-a-display-does-bodys-block-affect-span",{"name":178,"path":179,"isActive":115},"Есть HTML код. Будет ли font-weight на span влиять?","/technical-interview/tasks/there-is-an-html-code-will-font-weight-affect-span",{"name":181,"path":182,"isActive":115},"Flexbox и Grid, чем отличаются друг от друга?","/technical-interview/tasks/what-are-the-differences-between-flexbox-and-grid",{"name":184,"path":185,"isActive":115},"Заменяют ли Flexbox и Grid друг друга?","/technical-interview/tasks/do-flexbox-and-grid-replace-each-other",{"name":187,"path":188,"isActive":115},"Есть CSS и JS анимация. Какая между ними разница, что быстрее, что более удобно?","/technical-interview/tasks/there-are-css-and-js-animations-what-is-the-difference-between-them-and-which-is-faster-and-more-convenient",{"title":190,"list":191,"isOpened":115},"Git",[192,195,198],{"name":193,"path":194,"isActive":115},"Разрабатывал, взял закоммитил, запушил. Оказалось, что запушил не в ту ветку, точнее, коммит не в ту ветку. Какие действия?","/technical-interview/tasks/developed-it-committed-it-and-launched-it-it-turned-out-that-i-had-pushed-it-to-the-wrong-branch-or-rather-the-commit-was-in-the-wrong-branch-what-actions",{"name":196,"path":197,"isActive":115},"В git есть несколько вариантов слияния веток, какие? Чем отличаются?","/technical-interview/tasks/git-has-several-options-for-merging-branches-which-ones-how-are-they-different",{"name":199,"path":200,"isActive":115},"Какие существуют стратегии ветвления для работы команды? Что это такое?","/technical-interview/tasks/what-are-the-branching-strategies-for-the-team-what-is-it",{"title":202,"list":203,"isOpened":115},"HTML",[204],{"name":205,"path":206,"isActive":115},"Что такое HTML?","/technical-interview/tasks/what-is-html",{"title":208,"list":209,"isOpened":115},"JavaScript",[210,213,215,218,221,224,227,230,233,236,239,242,245,248,251,254,257,260,263,266,269,272,275,278,281,284,287,290,293,296,299,302,305,308,311,314,317,320,323,326,329,332,335,338,341,344],{"name":211,"path":212,"isActive":115},"Какие логические значения в console.log будут получены?","/technical-interview/tasks/prototype-what-logical-values-will-be-received-in-console-log",{"name":124,"path":214,"isActive":115},"/technical-interview/tasks/why-is-it-dangerous-to-write-directly-to-the-prototypes-of-basic-types",{"name":216,"path":217,"isActive":115},"Что вернёт следующий код? Object.create(null).hasOwnProperty('toString')","/technical-interview/tasks/what-will-the-following-code-return-object-create-null-has-own-property-to-string",{"name":219,"path":220,"isActive":115},"Какое значение выведет консоль с object.property?","/technical-interview/tasks/what-value-will-the-console-output-with-object-property",{"name":222,"path":223,"isActive":115},"Что выведется в console.log([arr[0](), arr[0]()])?","/technical-interview/tasks/what-will-be-displayed-in-console-log-arr-0-arr-0",{"name":225,"path":226,"isActive":115},"Что выведет console.log в результате выполнения цикла while?","/technical-interview/tasks/what-will-console-log-output-as-a-result-of-executing-the-while-loop",{"name":228,"path":229,"isActive":115},"Есть функция и объект. Напишите все известные вам способы, чтобы вывести в консоли значение x из объекта, используя функцию","/technical-interview/tasks/there-is-a-function-and-an-object-write-all-the-ways-you-know-to-output-the-value-of-x-from-an-object-in-the-console-using-the-function",{"name":231,"path":232,"isActive":115},"Что вернёт метод book.getUpperName()?","/technical-interview/tasks/what-will-the-book-get-upper-name-method-return",{"name":234,"path":235,"isActive":115},"Переменные объявлены следующим образом: a=3; b=«hello»;. Укажите правильное утверждение","/technical-interview/tasks/variables-are-declared-as-follows-specify-the-correct-statement",{"name":237,"path":238,"isActive":115},"Что выведет консоль в случае присвоения свойства массиву по строковому положительному индексу?","/technical-interview/tasks/what-will-the-console-display-if-a-property-is-assigned-to-an-array-using-a-positive-string-index",{"name":240,"path":241,"isActive":115},"Что выведет консоль в случае присвоения свойства массиву по строковому отрицательному индексу?","/technical-interview/tasks/what-will-the-console-display-if-a-property-is-assigned-to-an-array-using-a-negative-string-index",{"name":243,"path":244,"isActive":115},"Что выведет консоль в случае удаления элемента массива с помощью оператора delete?","/technical-interview/tasks/what-will-the-console-output-if-an-array-element-is-deleted-using-the-delete-operator",{"name":246,"path":247,"isActive":115},"Что вернёт этот код: typeof (function(){})()","/technical-interview/tasks/what-this-code-will-return-typeof-function",{"name":249,"path":250,"isActive":115},"Что получится в результате передачи объекта как аргумента в функцию и выполнения кода?","/technical-interview/tasks/what-will-happen-when-an-object-is-passed-as-an-argument-to-a-function-and-the-code-is-executed",{"name":252,"path":253,"isActive":115},"Какие способы объявления функции есть в JavaScript?","/technical-interview/tasks/what-are-the-ways-to-declare-a-function-in-javascript",{"name":255,"path":256,"isActive":115},"Что такое this в JavaScript?","/technical-interview/tasks/what-is-this-in-javascript",{"name":258,"path":259,"isActive":115},"Что такое Event Loop, как работает?","/technical-interview/tasks/what-is-an-event-loop-and-how-does-it-work",{"name":261,"path":262,"isActive":115},"Что будет, если вызвать typeof на необъявленной переменной?","/technical-interview/tasks/what-happens-if-you-call-typeof-on-an-undeclared-variable",{"name":264,"path":265,"isActive":115},"Что показывает оператор typeof в JavaScript?","/technical-interview/tasks/what-does-the-typeof-operator-show-in-javascript",{"name":267,"path":268,"isActive":115},"Какие типы данных существует в JavaScript?","/technical-interview/tasks/what-types-of-data-exist-in-javascript",{"name":270,"path":271,"isActive":115},"Какую структуру использовать для хранения упорядоченного списка строк в JavaScript?","/technical-interview/tasks/what-is-the-best-structure-to-use-for-storing-an-ordered-list-of-strings-in-javascript",{"name":273,"path":274,"isActive":115},"Что вернет typeof для массива?","/technical-interview/tasks/what-will-typeof-return-for-an-array",{"name":276,"path":277,"isActive":115},"Почему оператор typeof, применённый к массиву, возвращает объект?","/technical-interview/tasks/why-does-the-typeof-operator-applied-to-an-array-return-an-object",{"name":279,"path":280,"isActive":115},"Если нужно хранить список уникальных строк, какую структуру данных выбрать?","/technical-interview/tasks/if-you-need-to-store-a-list-of-unique-strings-which-data-structure-should-i-choose",{"name":282,"path":283,"isActive":115},"Что возвращает typeof для new Set в JavaScript?","/technical-interview/tasks/what-does-typeof-return-for-new-set-in-javascript",{"name":285,"path":286,"isActive":115},"Почему в JavaScript два объекта с одинаковым содержимым при сравнении возвращают false?","/technical-interview/tasks/why-do-two-objects-with-the-same-content-return-false-when-compared-in-javascript",{"name":288,"path":289,"isActive":115},"В чем разница между микро- и макро-тасками в JavaScript?","/technical-interview/tasks/what-is-the-difference-between-micro-and-macro-tasks-in-javascript",{"name":291,"path":292,"isActive":115},"arr.push(0) повлияет на массив так же, как если бы мы выполнили...","/technical-interview/tasks/arr-push-0-will-affect-the-array-in-the-same-way-as-if-we-performed",{"name":294,"path":295,"isActive":115},"Вернуть массив от 1 до n, где числа, кратные 3, заменены на 'fizz', кратные 5 - на 'buzz', а кратные и 3, и 5 одновременно - на 'fizzbuzz'","/technical-interview/tasks/returns-an-array-from-1-to-n-replacing-numbers-that-are-multiples-of-3-with-fizz-numbers-that-are-multiples-of-5-with-buzz-and-numbers-that-are-multiples-of-both-3-and-5-with-fizzbuzz",{"name":297,"path":298,"isActive":115},"Дана строка: 'one.two.three.four.five'. Необходимо из строки сделать вложенный объект","/technical-interview/tasks/the-string-one-two-three-four-five-is-given-it-is-necessary-to-make-a-nested-object-out-of-the-string",{"name":300,"path":301,"isActive":115},"Дано дерево (вложенный объект), надо найти сумму всех вершин","/technical-interview/tasks/given-a-tree-nested-object-it-is-necessary-to-find-the-sum-of-all-vertices",{"name":303,"path":304,"isActive":115},"Для каждого вложенного объекта нужно добавить свойство level, которое равняется числу - номер вложенности","/technical-interview/tasks/for-each-nested-object-you-need-to-add-the-level-property-which-is-equal-to-a-number-the-nesting-number",{"name":306,"path":307,"isActive":115},"Для каждой ветви дерева записать номер вложенности данной ветви","/technical-interview/tasks/for-each-branch-of-the-tree-write-down-the-nesting-number-of-this-branch",{"name":309,"path":310,"isActive":115},"Есть массив, в котором лежат объекты с датами, необходимо отсортировать даты по возрастанию","/technical-interview/tasks/there-is-an-array-containing-objects-with-dates-that-need-to-be-sorted-by-date",{"name":312,"path":313,"isActive":115},"Есть слова в массиве, необходимо определить, состоят ли они из одних и тех же букв","/technical-interview/tasks/there-are-words-in-the-array-it-is-necessary-to-determine-whether-they-consist-of-the-same-letters",{"name":315,"path":316,"isActive":115},"Есть строка, состоящая из разных скобок, необходимо проверить, закрыты ли все","/technical-interview/tasks/there-is-a-string-consisting-of-different-brackets-it-is-necessary-to-check-whether-all-are-closed",{"name":318,"path":319,"isActive":115}," Найти в массиве неповторяющиеся числа","/technical-interview/tasks/find-non-repeating-numbers-in-an-array",{"name":321,"path":322,"isActive":115},"Напишите функцию, который сделает из массива объект","/technical-interview/tasks/write-a-function-that-will-make-an-object-out-of-an-array",{"name":324,"path":325,"isActive":115},"Необходимо проверить, являются ли две строки анаграммами друг друга","/technical-interview/tasks/checks-whether-two-strings-are-anagrams-of-each-other",{"name":327,"path":328,"isActive":115},"Нечётные числа должны отсортироваться по возрастанию, а чётные должны остаться на своих местах","/technical-interview/tasks/odd-numbers-should-be-sorted-in-ascending-order-and-even-numbers-should-remain-in-their-original-positions",{"name":330,"path":331,"isActive":115},"Определить, является ли слово палиндромом","/technical-interview/tasks/determines-whether-a-word-is-a-palindrome",{"name":333,"path":334,"isActive":115},"«Расплющивание» массива","/technical-interview/tasks/flattening-the-array",{"name":336,"path":337,"isActive":115},"Реализовать функцию, принимающую аргументы \"*\", \"1\", \"b\", \"1c\" и возвращающую строку \"1*b*1c\"","/technical-interview/tasks/implement-a-function-that-accepts-arguments-1-b-1c-and-the-return-string-1-b-1c",{"name":339,"path":340,"isActive":115},"Сжатие строк","/technical-interview/tasks/string-compression",{"name":342,"path":343,"isActive":115},"Уникализация значений в массиве","/technical-interview/tasks/unifying-values-in-an-array",{"name":345,"path":346,"isActive":115},"Числа от 1 до 100 находятся в массиве, они хаотично перемешанные, но в нём не хватает одного числа из этой последовательности. Необходимо найти его","/technical-interview/tasks/the-numbers-from-1-to-100-are-in-the-array-they-are-randomly-mixed-but-it-lacks-one-number-from-this-sequence-it-is-necessary-to-find-him",{"title":348,"list":349,"isOpened":115},"React",[350,353,356,359,362,365,368],{"name":351,"path":352,"isActive":115},"Для чего нужен React, какие он решает проблемы?","/technical-interview/tasks/what-is-react-used-for-and-what-problems-does-it-solve",{"name":354,"path":355,"isActive":115},"Какой механизм лежит в основе оптимизации обновлений DOM в React?","/technical-interview/tasks/what-is-the-underlying-mechanism-for-optimizing-dom-updates-in-react",{"name":357,"path":358,"isActive":115},"Если убрать в React VDOM/Fiber, и вручную изменять DOM, разве это не оптимально?","/technical-interview/tasks/if-you-remove-the-vdom-fiber-in-react-and-manually-change-the-dom-isn-t-that-optimal",{"name":360,"path":361,"isActive":115},"Есть блок кода. Что в реальном DOM изменится после нажатия на кнопку?","/technical-interview/tasks/there-is-a-block-of-code-what-changes-in-the-real-dom-after-clicking-the-button",{"name":363,"path":364,"isActive":115},"Есть код, в котором список и кнопка. Что в реальном DOM изменится после нажатия на кнопку?","/technical-interview/tasks/there-is-a-code-in-which-there-is-a-list-and-a-button-what-will-change-in-the-real-dom-after-clicking-on-the-button",{"name":366,"path":367,"isActive":115},"Зачем нужен Redux (Mobx/Effector)? Зачем нужен менеджер состояния? Какие проблемы решает?","/technical-interview/tasks/why-do-we-need-redux-mobx-effector-why-do-we-need-a-state-manager-what-problems-does-it-solve",{"name":369,"path":370,"isActive":115},"Что мешает организовать централизованное состояние без менеджера состояния? Если организовать состояние механизмами реакта: контекстом, стейтом, в чем проблема? Что менеджеры состояния привносят?","/technical-interview/tasks/what-prevents-you-from-organizing-a-centralized-state-without-a-state-manager-if-you-organize-the-state-using-react-context-and-state-mechanisms-what-is-the-problem-what-do-state-managers-add",{"title":372,"list":373,"isOpened":115},"Алгоритмы",[374,377],{"name":375,"path":376,"isActive":115},"Что такое алгоритмическая сложность?","/technical-interview/tasks/what-is-algorithmic-complexity",{"name":378,"path":379,"isActive":115},"Какая алгоритмическая сложность у \"быстрой сортировки\"?","/technical-interview/tasks/what-is-the-algorithmic-complexity-of-quick-sort",{"title":381,"list":382,"isOpened":115},"Дебаггинг",[383],{"name":384,"path":385,"isActive":115},"Как диагностировать и исправить нежелательное изменение цвета фона по клику на кнопку, если исходный код сайта запутан и недоступен для прямого чтения?","/technical-interview/tasks/how-can-diagnose-and-fix-unwanted-background-color-changes-when-clicking-on-a-button-if-the-source-code-of-the-site-is-confusing-and-inaccessible-to-direct-reading",{"title":387,"list":388,"isOpened":115},"Компьютерные сети",[389,392,395,398,401,404,407,410,413,416,419,422,425,428,431,434,437,440,443,446],{"name":390,"path":391,"isActive":115},"Как браузер после ввода домена понимает, откуда брать сайт?","/technical-interview/tasks/how-does-the-browser-know-where-to-get-the-website-after-entering-the-domain",{"name":393,"path":394,"isActive":115},"Что такое DNS, как DNS находит нужный IP-адрес?","/technical-interview/tasks/what-is-dns-and-how-does-dns-find-the-correct-ip-address",{"name":396,"path":397,"isActive":115},"Как домен попадает в DNS в таблицу соответствия: домен – ip","/technical-interview/tasks/how-does-a-domain-get-into-the-dns-mapping-table-domain-ip",{"name":399,"path":400,"isActive":115},"Как браузер решает, какое соединение ему открывать, TCP или UDP?","/technical-interview/tasks/how-does-a-browser-decide-whether-to-open-a-tcp-or-udp-connection",{"name":402,"path":403,"isActive":115},"Ключевые отличия TCP и UDP","/technical-interview/tasks/key-differences-between-tcp-and-udp",{"name":405,"path":406,"isActive":115},"\"TCP/IP\" - кем является TCP, а кем IP в данном случае?","/technical-interview/tasks/tcp-ip-who-is-tcp-and-who-is-ip-in-this-case",{"name":408,"path":409,"isActive":115},"Что такое HTTP и из чего состоит?","/technical-interview/tasks/what-is-http-and-what-does-it-consist-of",{"name":411,"path":412,"isActive":115},"Что такое заголовки в HTTP и зачем они нужны?","/technical-interview/tasks/what-are-http-headers-and-why-do-we-need-them",{"name":414,"path":415,"isActive":115},"Что такое параметры в HTTP?","/technical-interview/tasks/what-are-http-parameters",{"name":417,"path":418,"isActive":115},"Где находится HTML-код в структуре HTTP-ответа?","/technical-interview/tasks/where-is-the-html-code-located-in-the-http-response-structure",{"name":420,"path":421,"isActive":115},"Чем отличаются 1.0, 1.1, 2.0, 3.0 версии HTTP?","/technical-interview/tasks/what-are-the-differences-between-http-versions-1-0-1-1-2-0-and-3-0",{"name":423,"path":424,"isActive":115},"Пользователь авторизован на сайте. Как сервер узнает об этом с последующими другими заходами, что «я – авторизованный пользователь»?","/technical-interview/tasks/the-user-is-logged-in-on-the-website-how-does-the-server-know-that-i-am-an-authorized-user-when-the-user-logs-in-again",{"name":426,"path":427,"isActive":115},"Что такое cookie?","/technical-interview/tasks/what-is-a-cookie",{"name":429,"path":430,"isActive":115},"Кто является инициатором записи cookie в браузере?","/technical-interview/tasks/who-initiates-the-cookie-recording-in-the-browser",{"name":432,"path":433,"isActive":115},"Есть ли возможность с клиента (с браузера) управлять cookie?","/technical-interview/tasks/is-it-possible-to-manage-cookies-from-the-client-browser",{"name":435,"path":436,"isActive":115},"Верно ли утверждение, что злоумышленник, контролирующий роутер и прослушивающий трафик, может получить логины и пароли от сайтов, на которые заходит клиент?","/technical-interview/tasks/is-it-true-that-an-attacker-who-controls-a-router-and-listens-to-traffic-can-obtain-logins-and-passwords-from-websites-that-a-client-visits",{"name":438,"path":439,"isActive":115},"Всё, что идет по HTTPS – оно защищено?","/technical-interview/tasks/is-everything-that-goes-through-https-secure",{"name":441,"path":442,"isActive":115},"Все данные зашифрованы, используется https. Хакер взламывает dns и делает подмену одного ip на другой, на фишинговый сайт. В этом случае, злоумышленник может получить данные (логин \\ пароль)?","/technical-interview/tasks/all-data-is-encrypted-https-is-used-let-s-assume-a-hacker-hacks-the-dns-and-makes-a-substitution-of-one-ip-for-another-a-phishing-site",{"name":444,"path":445,"isActive":115},"Есть веб-приложение. Помимо HTTP, какие протоколы того же уровня (Application Layer) можно дополнительно использовать в веб-приложении в браузере?","/technical-interview/tasks/there-is-a-web-application-in-addition-to-http-what-other-protocols-of-the-same-level-application-layer-can-be-used-in-the-web-application-in-browser",{"name":447,"path":448,"isActive":115},"Каким способом может выполняться авторизация пользователя на сайте?","/technical-interview/tasks/how-can-a-user-be-authorized-on-a-website",{"title":450,"list":451,"isOpened":115},"Отрисовка в браузере",[452,455,458,461,464,467],{"name":453,"path":454,"isActive":115},"Что происходит, когда HTTP прислал HTML? Что браузер дальше делает c HTML с учетом того, что она валидная?","/technical-interview/tasks/what-happens-when-http-sends-html-what-does-the-browser-do-with-this-html-given-that-it-is-valid",{"name":456,"path":457,"isActive":115},"Как браузер парсит JavaScript и изображения при рендеринге?","/technical-interview/tasks/how-the-browser-parses-javascript-and-images-when-rendering",{"name":459,"path":460,"isActive":115},"Что в браузере блокирует рендеринг страницы?","/technical-interview/tasks/what-is-blocking-the-page-rendering-in-the-browser",{"name":462,"path":463,"isActive":115},"Что такое DOM в браузере? Что такое CSSOM?","/technical-interview/tasks/what-is-dom-in-a-browser-what-is-cssom",{"name":465,"path":466,"isActive":115},"Что является узлами в DOM?","/technical-interview/tasks/what-are-nodes-in-the-dom",{"name":468,"path":469,"isActive":115},"Из чего состоит CSSOM?","/technical-interview/tasks/what-does-cssom-consist-of",{"title":471,"list":472,"isOpened":115},"Ревью кода",[473],{"name":474,"path":475,"isActive":115},"По каким характеристикам, ревьюер понимает, что данный код - хороший, а этот код - плохой?","/technical-interview/tasks/how-does-a-reviewer-know-which-code-is-good-and-which-code-is-bad",{"title":477,"list":478,"isOpened":115},"Теория вероятности",[479,482,485],{"name":480,"path":481,"isActive":115},"В комнате три человека. Какова вероятность того, что хотя бы двое из них одного пола? То есть два и более.","/technical-interview/tasks/there-are-three-people-in-the-room-what-is-the-probability-that-at-least-two-of-them-are-of-the-same-sex-that-is-two-or-more",{"name":483,"path":484,"isActive":115},"Есть монета. Ее подбрасывают пять раз подряд. Каждый раз записывается, что выпало - орел или решка. Сколько разных последовательностей орлов и решек может при этом получиться?","/technical-interview/tasks/there-is-a-coin-it-is-tossed-five-times-in-a-row-each-time-it-is-recorded-whether-it-lands-on-heads-or-tails-how-many-different-sequences-of-heads-and-tails-can-be-obtained",{"name":486,"path":487,"isActive":115},"Как гарантированно найти лёгкую фальшивую монету среди 8 за минимальное число взвешиваний на чашечных весах?","/technical-interview/tasks/how-can-you-guarantee-to-find-an-easy-fake-coin-among-8-in-the-minimum-number-of-weighings-on-a-balance-scale",{"slugs":489},[490,493,495,497,499,502,505,507,509,511,513,515,518,520,522,524,526,528,530,532,534,536,538,540,542,544,546,548,550,552,554,556,558,560,562,564,566,568,570,572,574,576,578,580,582,584,586,588,590,592,594,596,599,601,603,605,607,609,611,613,615,617,619,621,623,625,627,629,631,633,635,637,639,641,643,645,647,649,651,653,655,657,659,661,663,665,667,669,671,673,675,677,679,681,683,685,687,689,691,693,695,697,699,700,702,704,706,708],{"name":491,"value":492},"Теоретические задания","theoretical-tasks",{"name":246,"value":494},"what-this-code-will-return-typeof-function",{"name":146,"value":496},"where-to-begin",{"name":124,"value":498},"why-is-it-dangerous-to-write-directly-to-the-prototypes-of-basic-types",{"name":500,"value":501},"Backend","backend",{"name":503,"value":504},"Frontend","frontend",{"name":211,"value":506},"prototype-what-logical-values-will-be-received-in-console-log",{"name":327,"value":508},"odd-numbers-should-be-sorted-in-ascending-order-and-even-numbers-should-remain-in-their-original-positions",{"name":318,"value":510},"find-non-repeating-numbers-in-an-array",{"name":291,"value":512},"arr-push-0-will-affect-the-array-in-the-same-way-as-if-we-performed",{"name":297,"value":514},"the-string-one-two-three-four-five-is-given-it-is-necessary-to-make-a-nested-object-out-of-the-string",{"name":516,"value":517},"Реализовать функцию, похоже как в Jquery","implement-a-function-similar-to-jquery",{"name":303,"value":519},"for-each-nested-object-you-need-to-add-the-level-property-which-is-equal-to-a-number-the-nesting-number",{"name":219,"value":521},"what-value-will-the-console-output-with-object-property",{"name":222,"value":523},"what-will-be-displayed-in-console-log-arr-0-arr-0",{"name":294,"value":525},"returns-an-array-from-1-to-n-replacing-numbers-that-are-multiples-of-3-with-fizz-numbers-that-are-multiples-of-5-with-buzz-and-numbers-that-are-multiples-of-both-3-and-5-with-fizzbuzz",{"name":324,"value":527},"checks-whether-two-strings-are-anagrams-of-each-other",{"name":330,"value":529},"determines-whether-a-word-is-a-palindrome",{"name":309,"value":531},"there-is-an-array-containing-objects-with-dates-that-need-to-be-sorted-by-date",{"name":336,"value":533},"implement-a-function-that-accepts-arguments-1-b-1c-and-the-return-string-1-b-1c",{"name":300,"value":535},"given-a-tree-nested-object-it-is-necessary-to-find-the-sum-of-all-vertices",{"name":306,"value":537},"for-each-branch-of-the-tree-write-down-the-nesting-number-of-this-branch",{"name":312,"value":539},"there-are-words-in-the-array-it-is-necessary-to-determine-whether-they-consist-of-the-same-letters",{"name":345,"value":541},"the-numbers-from-1-to-100-are-in-the-array-they-are-randomly-mixed-but-it-lacks-one-number-from-this-sequence-it-is-necessary-to-find-him",{"name":315,"value":543},"there-is-a-string-consisting-of-different-brackets-it-is-necessary-to-check-whether-all-are-closed",{"name":321,"value":545},"write-a-function-that-will-make-an-object-out-of-an-array",{"name":225,"value":547},"what-will-console-log-output-as-a-result-of-executing-the-while-loop",{"name":228,"value":549},"there-is-a-function-and-an-object-write-all-the-ways-you-know-to-output-the-value-of-x-from-an-object-in-the-console-using-the-function",{"name":240,"value":551},"what-will-the-console-display-if-a-property-is-assigned-to-an-array-using-a-negative-string-index",{"name":243,"value":553},"what-will-the-console-output-if-an-array-element-is-deleted-using-the-delete-operator",{"name":342,"value":555},"unifying-values-in-an-array",{"name":333,"value":557},"flattening-the-array",{"name":231,"value":559},"what-will-the-book-get-upper-name-method-return",{"name":339,"value":561},"string-compression",{"name":237,"value":563},"what-will-the-console-display-if-a-property-is-assigned-to-an-array-using-a-positive-string-index",{"name":249,"value":565},"what-will-happen-when-an-object-is-passed-as-an-argument-to-a-function-and-the-code-is-executed",{"name":390,"value":567},"how-does-the-browser-know-where-to-get-the-website-after-entering-the-domain",{"name":396,"value":569},"how-does-a-domain-get-into-the-dns-mapping-table-domain-ip",{"name":399,"value":571},"how-does-a-browser-decide-whether-to-open-a-tcp-or-udp-connection",{"name":402,"value":573},"key-differences-between-tcp-and-udp",{"name":405,"value":575},"tcp-ip-who-is-tcp-and-who-is-ip-in-this-case",{"name":408,"value":577},"what-is-http-and-what-does-it-consist-of",{"name":411,"value":579},"what-are-http-headers-and-why-do-we-need-them",{"name":414,"value":581},"what-are-http-parameters",{"name":417,"value":583},"where-is-the-html-code-located-in-the-http-response-structure",{"name":205,"value":585},"what-is-html",{"name":420,"value":587},"what-are-the-differences-between-http-versions-1-0-1-1-2-0-and-3-0",{"name":423,"value":589},"the-user-is-logged-in-on-the-website-how-does-the-server-know-that-i-am-an-authorized-user-when-the-user-logs-in-again",{"name":426,"value":591},"what-is-a-cookie",{"name":429,"value":593},"who-initiates-the-cookie-recording-in-the-browser",{"name":432,"value":595},"is-it-possible-to-manage-cookies-from-the-client-browser",{"name":597,"value":598},"Лайвкодинг","livecoding",{"name":216,"value":600},"what-will-the-following-code-return-object-create-null-has-own-property-to-string",{"name":438,"value":602},"is-everything-that-goes-through-https-secure",{"name":441,"value":604},"all-data-is-encrypted-https-is-used-let-s-assume-a-hacker-hacks-the-dns-and-makes-a-substitution-of-one-ip-for-another-a-phishing-site",{"name":444,"value":606},"there-is-a-web-application-in-addition-to-http-what-other-protocols-of-the-same-level-application-layer-can-be-used-in-the-web-application-in-browser",{"name":456,"value":608},"how-the-browser-parses-javascript-and-images-when-rendering",{"name":453,"value":610},"what-happens-when-http-sends-html-what-does-the-browser-do-with-this-html-given-that-it-is-valid",{"name":459,"value":612},"what-is-blocking-the-page-rendering-in-the-browser",{"name":462,"value":614},"what-is-dom-in-a-browser-what-is-cssom",{"name":465,"value":616},"what-are-nodes-in-the-dom",{"name":468,"value":618},"what-does-cssom-consist-of",{"name":166,"value":620},"the-html-code-is-given-what-will-be-the-color-of-the-some-dummy-text",{"name":169,"value":622},"there-is-a-template-for-html-and-css-code-what-color-will-the-text-thus-constant-have",{"name":172,"value":624},"there-is-a-template-for-embedded-html-code-what-will-be-the-color-of-the-one-more-dummy-text",{"name":175,"value":626},"there-is-a-template-for-embedded-html-code-will-there-be-a-display-does-bodys-block-affect-span",{"name":178,"value":628},"there-is-an-html-code-will-font-weight-affect-span",{"name":181,"value":630},"what-are-the-differences-between-flexbox-and-grid",{"name":184,"value":632},"do-flexbox-and-grid-replace-each-other",{"name":187,"value":634},"there-are-css-and-js-animations-what-is-the-difference-between-them-and-which-is-faster-and-more-convenient",{"name":150,"value":636},"tasks",{"name":252,"value":638},"what-are-the-ways-to-declare-a-function-in-javascript",{"name":255,"value":640},"what-is-this-in-javascript",{"name":258,"value":642},"what-is-an-event-loop-and-how-does-it-work",{"name":261,"value":644},"what-happens-if-you-call-typeof-on-an-undeclared-variable",{"name":264,"value":646},"what-does-the-typeof-operator-show-in-javascript",{"name":267,"value":648},"what-types-of-data-exist-in-javascript",{"name":270,"value":650},"what-is-the-best-structure-to-use-for-storing-an-ordered-list-of-strings-in-javascript",{"name":273,"value":652},"what-will-typeof-return-for-an-array",{"name":276,"value":654},"why-does-the-typeof-operator-applied-to-an-array-return-an-object",{"name":279,"value":656},"if-you-need-to-store-a-list-of-unique-strings-which-data-structure-should-i-choose",{"name":282,"value":658},"what-does-typeof-return-for-new-set-in-javascript",{"name":351,"value":660},"what-is-react-used-for-and-what-problems-does-it-solve",{"name":357,"value":662},"if-you-remove-the-vdom-fiber-in-react-and-manually-change-the-dom-isn-t-that-optimal",{"name":360,"value":664},"there-is-a-block-of-code-what-changes-in-the-real-dom-after-clicking-the-button",{"name":363,"value":666},"there-is-a-code-in-which-there-is-a-list-and-a-button-what-will-change-in-the-real-dom-after-clicking-on-the-button",{"name":366,"value":668},"why-do-we-need-redux-mobx-effector-why-do-we-need-a-state-manager-what-problems-does-it-solve",{"name":384,"value":670},"how-can-diagnose-and-fix-unwanted-background-color-changes-when-clicking-on-a-button-if-the-source-code-of-the-site-is-confusing-and-inaccessible-to-direct-reading",{"name":193,"value":672},"developed-it-committed-it-and-launched-it-it-turned-out-that-i-had-pushed-it-to-the-wrong-branch-or-rather-the-commit-was-in-the-wrong-branch-what-actions",{"name":196,"value":674},"git-has-several-options-for-merging-branches-which-ones-how-are-they-different",{"name":199,"value":676},"what-are-the-branching-strategies-for-the-team-what-is-it",{"name":474,"value":678},"how-does-a-reviewer-know-which-code-is-good-and-which-code-is-bad",{"name":157,"value":680},"here-is-a-fragment-of-a-bash-script-cd-mkdir-foo-what-is-happening-in-this-script",{"name":160,"value":682},"here-is-a-fragment-of-a-bash-script-target-ps-af-grep-1-head-n-1",{"name":375,"value":684},"what-is-algorithmic-complexity",{"name":378,"value":686},"what-is-the-algorithmic-complexity-of-quick-sort",{"name":285,"value":688},"why-do-two-objects-with-the-same-content-return-false-when-compared-in-javascript",{"name":447,"value":690},"how-can-a-user-be-authorized-on-a-website",{"name":288,"value":692},"what-is-the-difference-between-micro-and-macro-tasks-in-javascript",{"name":480,"value":694},"there-are-three-people-in-the-room-what-is-the-probability-that-at-least-two-of-them-are-of-the-same-sex-that-is-two-or-more",{"name":483,"value":696},"there-is-a-coin-it-is-tossed-five-times-in-a-row-each-time-it-is-recorded-whether-it-lands-on-heads-or-tails-how-many-different-sequences-of-heads-and-tails-can-be-obtained",{"name":486,"value":698},"how-can-you-guarantee-to-find-an-easy-fake-coin-among-8-in-the-minimum-number-of-weighings-on-a-balance-scale",{"name":140,"value":141},{"name":435,"value":701},"is-it-true-that-an-attacker-who-controls-a-router-and-listens-to-traffic-can-obtain-logins-and-passwords-from-websites-that-a-client-visits",{"name":393,"value":703},"what-is-dns-and-how-does-dns-find-the-correct-ip-address",{"name":234,"value":705},"variables-are-declared-as-follows-specify-the-correct-statement",{"name":354,"value":707},"what-is-the-underlying-mechanism-for-optimizing-dom-updates-in-react",{"name":369,"value":709},"what-prevents-you-from-organizing-a-centralized-state-without-a-state-manager-if-you-organize-the-state-using-react-context-and-state-mechanisms-what-is-the-problem-what-do-state-managers-add",{"cooperation":711,"copyright":714,"reportError":715,"socialNetwork":717},{"link":712,"title":713},"https://t.me/baurinanton","Сотрудничество","© “GOOD WEB JOB!”",{"label":716,"link":712},"Сообщить об ошибке",{"label":718,"socialNetworkList":719},"Мы в соцсетях:",[720,723,726],{"icon":19,"link":721,"title":722},"https://max.ru/u/f9LHodD0cOKMaukdnnahTeL5pwvjrPfUaZ4S8_1rsNy9I9qsmc9Ar3kP_y8","Max",{"icon":724,"link":712,"title":725},"ic:baseline-telegram","Telegram",{"icon":727,"link":728,"title":729},"ri:vk-fill","https://vk.com/baurinanton","VK",{"data":731,"body":732},{},{"type":733,"children":734},"root",[735],{"type":736,"tag":737,"props":738,"children":739},"element","p",{},[740],{"type":741,"value":124},"text",{"data":743,"body":744},{},{"type":733,"children":745},[746],{"type":736,"tag":737,"props":747,"children":748},{},[749],{"type":741,"value":111},{"data":751,"body":752},{},{"type":733,"children":753},[754],{"type":736,"tag":737,"props":755,"children":756},{},[757,759,766,768,774],{"type":741,"value":758},"Опасность заключается в том, что строгий режим запрещает любые изменения прототипов базовых типов, поэтому приложение перестаёт запускаться в современных браузерах. В результате попытка добавить метод в ",{"type":736,"tag":760,"props":761,"children":763},"code",{"className":762},[],[764],{"type":741,"value":765},"Array.prototype",{"type":741,"value":767}," или ",{"type":736,"tag":760,"props":769,"children":771},{"className":770},[],[772],{"type":741,"value":773},"Object.prototype",{"type":741,"value":775}," приводит к синтаксической ошибке на этапе разбора кода, и выполнение становится невозможным.",{"data":777,"body":778},{},{"type":733,"children":779},[780],{"type":736,"tag":737,"props":781,"children":782},{},[783],{"type":741,"value":118},{"data":785,"body":786},{},{"type":733,"children":787},[788],{"type":736,"tag":737,"props":789,"children":790},{},[791,793,799],{"type":741,"value":792},"Опасность сводится к потере доступа к приватным полям классов: при добавлении методов в прототипы встроенных типов приватные поля (",{"type":736,"tag":760,"props":794,"children":796},{"className":795},[],[797],{"type":741,"value":798},"#field",{"type":741,"value":800},") начинают конфликтовать с цепочкой прототипов. Это вызывает массовые ошибки обращения к приватным данным и делает классы непригодными для применения в реальных проектах.",{"data":802,"body":803},{},{"type":733,"children":804},[805],{"type":736,"tag":737,"props":806,"children":807},{},[808,810,816],{"type":741,"value":809},"Для объяснения достаточно представить прототип как “общий источник методов” для всех значений типа и помнить: запись в ",{"type":736,"tag":760,"props":811,"children":813},{"className":812},[],[814],{"type":741,"value":815},"*.prototype",{"type":741,"value":817}," меняет поведение всей программы, поэтому ошибка становится глобальной, а при обработке внешних данных возможны сценарии загрязнения прототипов.",{"data":819,"body":820},{},{"type":733,"children":821},[822],{"type":736,"tag":737,"props":823,"children":824},{},[825,831],{"type":736,"tag":826,"props":827,"children":828},"strong",{},[829],{"type":741,"value":830},"Правильный ответ: 1",{"type":741,"value":832}," - Опасность связана с тем, что добавленные свойства и методы становятся общими для всех экземпляров типа, поэтому сторонний код может начать работать иначе, а перечисление свойств и проверки наличия ключей способны давать неожиданные результаты. Дополнительно возникают конфликты имён с библиотеками и будущими стандартными методами, поэтому практики качества кода часто запрещают такие изменения.",{"data":834,"body":835},{},{"type":733,"children":836},[837,864,869,874],{"type":736,"tag":737,"props":838,"children":839},{},[840,842,847,849,855,857,862],{"type":741,"value":841},"В JavaScript у объектов есть внутренняя ссылка на прототип (часто объясняется как “цепочка прототипов”), по которой движок ищет свойства и методы, если их нет в самом объекте. У массивов методы лежат в ",{"type":736,"tag":760,"props":843,"children":845},{"className":844},[],[846],{"type":741,"value":765},{"type":741,"value":848},", у строк — в ",{"type":736,"tag":760,"props":850,"children":852},{"className":851},[],[853],{"type":741,"value":854},"String.prototype",{"type":741,"value":856},", и почти все объекты в итоге наследуют от ",{"type":736,"tag":760,"props":858,"children":860},{"className":859},[],[861],{"type":741,"value":773},{"type":741,"value":863},".",{"type":736,"tag":737,"props":865,"children":866},{},[867],{"type":741,"value":868},"Механизм поиска свойства упрощённо выглядит так: сначала проверяются собственные свойства объекта, затем свойства прототипа, затем прототипа прототипа и так далее, пока цепочка не закончится.",{"type":736,"tag":737,"props":870,"children":871},{},[872],{"type":741,"value":873},"Схема поиска свойства:",{"type":736,"tag":875,"props":876,"children":880},"pre",{"className":877,"code":879,"language":741},[878],"language-text","Object instance\n  |\n  v\n(собственные свойства)\n  |\n  v\nSomeType.prototype\n  |\n  v\nObject.prototype\n  |\n  v\nnull\n",[881],{"type":736,"tag":760,"props":882,"children":884},{"__ignoreMap":883},"",[885],{"type":741,"value":879},{"data":887,"body":888},{},{"type":733,"children":889},[890],{"type":736,"tag":737,"props":891,"children":892},{},[893,895,901],{"type":741,"value":894},"Запись в ",{"type":736,"tag":760,"props":896,"children":898},{"className":897},[],[899],{"type":741,"value":900},"SomeType.prototype",{"type":741,"value":902}," меняет “общую базу методов” для всех экземпляров этого типа, включая уже созданные.",{"data":904,"body":905},{},{"type":733,"children":906},[907,920,925],{"type":736,"tag":737,"props":908,"children":909},{},[910,912,918],{"type":741,"value":911},"Добавление, например, ",{"type":736,"tag":760,"props":913,"children":915},{"className":914},[],[916],{"type":741,"value":917},"Array.prototype.myMethod",{"type":741,"value":919}," влияет на все массивы в приложении и во всех подключённых зависимостях. Из-за этого ошибка может проявиться в другом месте: код меняется в одном файле, а ломается логика в библиотеке, которая никогда не ожидала появления нового свойства с таким именем.",{"type":736,"tag":737,"props":921,"children":922},{},[923],{"type":741,"value":924},"Пример “глобальности”:",{"type":736,"tag":875,"props":926,"children":929},{"className":927,"code":928,"language":741},[878],"/ Изменение прототипа массива (опасная практика)\nArray.prototype.sum = function () {\n  return this.reduce((a, b) => a + b, 0);\n};\n\nconsole.log([1, 2, 3].sum()); // 6\n\n// Важно: метод появился у всех массивов, включая те, что создаются в стороннем коде\n",[930],{"type":736,"tag":760,"props":931,"children":932},{"__ignoreMap":883},[933],{"type":741,"value":928},{"data":935,"body":936},{},{"type":733,"children":937},[938,943,963,968],{"type":736,"tag":737,"props":939,"children":940},{},[941],{"type":741,"value":942},"Если добавляется метод с популярным именем, то существует риск, что:",{"type":736,"tag":944,"props":945,"children":946},"ul",{},[947,953,958],{"type":736,"tag":948,"props":949,"children":950},"li",{},[951],{"type":741,"value":952},"библиотека уже добавляет метод с таким же именем, но с другой логикой;",{"type":736,"tag":948,"props":954,"children":955},{},[956],{"type":741,"value":957},"другая часть проекта рассчитывает, что такого метода не существует;",{"type":736,"tag":948,"props":959,"children":960},{},[961],{"type":741,"value":962},"среда выполнения позже добавит стандартный метод с таким именем, но с иным контрактом.",{"type":736,"tag":737,"props":964,"children":965},{},[966],{"type":741,"value":967},"Пример конфликта имён (идея упрощена):",{"type":736,"tag":875,"props":969,"children":972},{"className":970,"code":971,"language":741},[878],"// Приложение добавляет метод с коротким именем\nString.prototype.format = function () {\n  return \"локальная логика форматирования\";\n};\n\n// Где-то в зависимости ожидается другое поведение format()\n// или в будущем стандарт добавит одноимённый метод с другой семантикой\nconsole.log(\"x\".format());\n",[973],{"type":736,"tag":760,"props":974,"children":975},{"__ignoreMap":883},[976],{"type":741,"value":971},{"data":978,"body":979},{},{"type":733,"children":980},[981,994,999,1008],{"type":736,"tag":737,"props":982,"children":983},{},[984,986,992],{"type":741,"value":985},"Некоторые конструкции перебирают свойства, включая унаследованные (например, ",{"type":736,"tag":760,"props":987,"children":989},{"className":988},[],[990],{"type":741,"value":991},"for...in",{"type":741,"value":993},"). Если в прототип добавлено перечислимое свойство, оно может внезапно появиться в переборе и сломать алгоритм, который ожидает только индексы массива или только реальные поля объекта.",{"type":736,"tag":737,"props":995,"children":996},{},[997],{"type":741,"value":998},"Пример ошибки при перечислении:",{"type":736,"tag":875,"props":1000,"children":1003},{"className":1001,"code":1002,"language":741},[878],"// Добавление перечислимого свойства в прототип (опасно)\nArray.prototype.extra = 123;\n\nconst arr = [10, 20];\n\nfor (const k in arr) {\n  // Ожидаются \"0\" и \"1\", но также может появиться \"extra\"\n  console.log(k);\n}\n",[1004],{"type":736,"tag":760,"props":1005,"children":1006},{"__ignoreMap":883},[1007],{"type":741,"value":1002},{"type":736,"tag":737,"props":1009,"children":1010},{},[1011,1013,1019],{"type":741,"value":1012},"Даже если метод добавляется через ",{"type":736,"tag":760,"props":1014,"children":1016},{"className":1015},[],[1017],{"type":741,"value":1018},"Object.defineProperty(..., { enumerable: false })",{"type":741,"value":1020},", остаются другие риски: глобальное изменение поведения, конфликты имён, влияние на проверки наличия свойства и на совместимость.",{"data":1022,"body":1023},{},{"type":733,"children":1024},[1025,1037,1042,1047],{"type":736,"tag":737,"props":1026,"children":1027},{},[1028,1030,1035],{"type":741,"value":1029},"Prototype pollution — ситуация, когда из-за обработки непроверенных данных в прототипы (часто в ",{"type":736,"tag":760,"props":1031,"children":1033},{"className":1032},[],[1034],{"type":741,"value":773},{"type":741,"value":1036},") попадают новые свойства. После этого эти свойства становятся “видимыми” для многих объектов и способны повлиять на проверки, условия и настройки по всему приложению.",{"type":736,"tag":737,"props":1038,"children":1039},{},[1040],{"type":741,"value":1041},"Типичный источник проблемы — “слияние” объектов, пришедших извне (например, из JSON), без фильтрации опасных ключей.",{"type":736,"tag":737,"props":1043,"children":1044},{},[1045],{"type":741,"value":1046},"Пример, демонстрирующий идею (упрощённо):",{"type":736,"tag":875,"props":1048,"children":1051},{"className":1049,"code":1050,"language":741},[878],"function merge(target, source) {\n  for (const key in source) {\n    target[key] = source[key];\n  }\n  return target;\n}\n\n// Непроверенный ввод\nconst payload = JSON.parse('{\"__proto__\":{\"isAdmin\":true}}');\n\nconst user = {};\nmerge(user, payload);\n\n// Опасный эффект: свойство может начать \"как бы существовать\" у многих объектов\nconst obj = {};\nconsole.log(obj.isAdmin); // потенциально true в уязвимых сценариях\n",[1052],{"type":736,"tag":760,"props":1053,"children":1054},{"__ignoreMap":883},[1055],{"type":741,"value":1050},{"data":1057,"body":1058},{},{"type":733,"children":1059},[1060],{"type":736,"tag":737,"props":1061,"children":1062},{},[1063,1065,1071],{"type":741,"value":1064},"Даже “маленькое” изменение прототипов может стать причиной обхода проверок доступа, если где-то в коде используется логика наподобие ",{"type":736,"tag":760,"props":1066,"children":1068},{"className":1067},[],[1069],{"type":741,"value":1070},"if (obj.isAdmin) ...",{"type":741,"value":1072}," без строгой валидации источника этого значения.",{"data":1074,"body":1075},{},{"type":733,"children":1076},[1077],{"type":736,"tag":737,"props":1078,"children":1079},{},[1080],{"type":741,"value":1081},"Надёжнее не менять встроенные прототипы, а выносить функциональность в обычные функции, модули или классы-обёртки. Такой код проще тестировать, проще читать и невозможно “случайно” навязать всем объектам в программе.",{"data":1083,"body":1084},{},{"type":733,"children":1085},[1086,1099,1108],{"type":736,"tag":737,"props":1087,"children":1088},{},[1089,1091,1097],{"type":741,"value":1090},"Пример замены ",{"type":736,"tag":760,"props":1092,"children":1094},{"className":1093},[],[1095],{"type":741,"value":1096},"Array.prototype.unique",{"type":741,"value":1098}," на обычную функцию:",{"type":736,"tag":875,"props":1100,"children":1103},{"className":1101,"code":1102,"language":741},[878],"function unique(arr) {\n  return Array.from(new Set(arr));\n}\n\nconsole.log(unique([1, 1, 2])); // [1, 2]\n",[1104],{"type":736,"tag":760,"props":1105,"children":1106},{"__ignoreMap":883},[1107],{"type":741,"value":1102},{"type":736,"tag":737,"props":1109,"children":1110},{},[1111],{"type":741,"value":1112},"Плюсы: отсутствуют глобальные побочные эффекты, проще типизировать, проще переиспользовать, легче сопровождать.",{"data":1114,"body":1115},{},{"type":733,"children":1116},[1117,1137],{"type":736,"tag":737,"props":1118,"children":1119},{},[1120,1122,1128,1130,1135],{"type":741,"value":1121},"Если необходима структура “ключ → значение”, часто безопаснее ",{"type":736,"tag":760,"props":1123,"children":1125},{"className":1124},[],[1126],{"type":741,"value":1127},"Map",{"type":741,"value":1129},", потому что он не использует ",{"type":736,"tag":760,"props":1131,"children":1133},{"className":1132},[],[1134],{"type":741,"value":773},{"type":741,"value":1136}," как часть механики доступа к ключам.",{"type":736,"tag":875,"props":1138,"children":1141},{"className":1139,"code":1140,"language":741},[878],"const m = new Map();\nm.set(\"__proto__\", \"ok\");\nconsole.log(m.get(\"__proto__\")); // \"ok\"\n",[1142],{"type":736,"tag":760,"props":1143,"children":1144},{"__ignoreMap":883},[1145],{"type":741,"value":1140},{"data":1147,"body":1148},{},{"type":733,"children":1149},[1150,1155,1178,1183],{"type":736,"tag":737,"props":1151,"children":1152},{},[1153],{"type":741,"value":1154},"Единственный относительно оправданный случай изменения прототипа — полифил стандартного метода для старого окружения, когда:",{"type":736,"tag":944,"props":1156,"children":1157},{},[1158,1163,1168,1173],{"type":736,"tag":948,"props":1159,"children":1160},{},[1161],{"type":741,"value":1162},"метод отсутствует;",{"type":736,"tag":948,"props":1164,"children":1165},{},[1166],{"type":741,"value":1167},"добавление точно повторяет контракт стандарта;",{"type":736,"tag":948,"props":1169,"children":1170},{},[1171],{"type":741,"value":1172},"свойство делается неперечислимым;",{"type":736,"tag":948,"props":1174,"children":1175},{},[1176],{"type":741,"value":1177},"решение документировано и контролируется (обычно в одном месте проекта).",{"type":736,"tag":737,"props":1179,"children":1180},{},[1181],{"type":741,"value":1182},"Пример “аккуратного” добавления (упрощённая форма):",{"type":736,"tag":875,"props":1184,"children":1187},{"className":1185,"code":1186,"language":741},[878],"if (!Array.prototype.myPolyfilledMethod) {\n  Object.defineProperty(Array.prototype, \"myPolyfilledMethod\", {\n    value: function () {\n      return \"реализация\";\n    },\n    enumerable: false,\n    writable: true,\n    configurable: true\n  });\n}\n",[1188],{"type":736,"tag":760,"props":1189,"children":1190},{"__ignoreMap":883},[1191],{"type":741,"value":1186},{"data":1193,"body":1194},{},{"type":733,"children":1195},[1196],{"type":736,"tag":737,"props":1197,"children":1198},{},[1199],{"type":741,"value":88},{"data":1201,"body":1202},{},{"type":733,"children":1203},[1204,1232,1237],{"type":736,"tag":737,"props":1205,"children":1206},{},[1207,1209,1215,1217,1223,1224,1230],{"type":741,"value":1208},"При обработке внешнего ввода следует исключать опасные ключи (",{"type":736,"tag":760,"props":1210,"children":1212},{"className":1211},[],[1213],{"type":741,"value":1214},"__proto__",{"type":741,"value":1216},", ",{"type":736,"tag":760,"props":1218,"children":1220},{"className":1219},[],[1221],{"type":741,"value":1222},"constructor",{"type":741,"value":1216},{"type":736,"tag":760,"props":1225,"children":1227},{"className":1226},[],[1228],{"type":741,"value":1229},"prototype",{"type":741,"value":1231},") и по возможности создавать объекты без прототипа для роли “чистого словаря”.",{"type":736,"tag":737,"props":1233,"children":1234},{},[1235],{"type":741,"value":1236},"Пример:",{"type":736,"tag":875,"props":1238,"children":1241},{"className":1239,"code":1240,"language":741},[878],"function safeAssign(target, source) {\n  for (const key of Object.keys(source)) {\n    if (key === \"__proto__\" || key === \"constructor\" || key === \"prototype\") continue;\n    target[key] = source[key];\n  }\n  return target;\n}\n\nconst dict = Object.create(null);\nsafeAssign(dict, JSON.parse('{\"a\":1,\"__proto__\":{\"polluted\":true}}'));\n\nconsole.log(dict.a); // 1\n",[1242],{"type":736,"tag":760,"props":1243,"children":1244},{"__ignoreMap":883},[1245],{"type":741,"value":1240},{"data":1247,"body":1248},{},{"type":733,"children":1249},[1250],{"type":736,"tag":1251,"props":1252,"children":1253},"table",{},[1254,1278],{"type":736,"tag":1255,"props":1256,"children":1257},"thead",{},[1258],{"type":736,"tag":1259,"props":1260,"children":1261},"tr",{},[1262,1268,1273],{"type":736,"tag":1263,"props":1264,"children":1265},"th",{},[1266],{"type":741,"value":1267},"Риск",{"type":736,"tag":1263,"props":1269,"children":1270},{},[1271],{"type":741,"value":1272},"Как проявляется",{"type":736,"tag":1263,"props":1274,"children":1275},{},[1276],{"type":741,"value":1277},"Безопасная альтернатива",{"type":736,"tag":1279,"props":1280,"children":1281},"tbody",{},[1282,1301,1319,1350],{"type":736,"tag":1259,"props":1283,"children":1284},{},[1285,1291,1296],{"type":736,"tag":1286,"props":1287,"children":1288},"td",{},[1289],{"type":741,"value":1290},"Глобальные изменения поведения",{"type":736,"tag":1286,"props":1292,"children":1293},{},[1294],{"type":741,"value":1295},"“Ломается” код в другом модуле или зависимости",{"type":736,"tag":1286,"props":1297,"children":1298},{},[1299],{"type":741,"value":1300},"Утилитные функции, отдельные модули",{"type":736,"tag":1259,"props":1302,"children":1303},{},[1304,1309,1314],{"type":736,"tag":1286,"props":1305,"children":1306},{},[1307],{"type":741,"value":1308},"Конфликты имён",{"type":736,"tag":1286,"props":1310,"children":1311},{},[1312],{"type":741,"value":1313},"Одинаковое имя метода, разный контракт",{"type":736,"tag":1286,"props":1315,"children":1316},{},[1317],{"type":741,"value":1318},"Явный импорт функции, неймспейсы",{"type":736,"tag":1259,"props":1320,"children":1321},{},[1322,1327,1339],{"type":736,"tag":1286,"props":1323,"children":1324},{},[1325],{"type":741,"value":1326},"Неожиданное перечисление",{"type":736,"tag":1286,"props":1328,"children":1329},{},[1330,1332,1337],{"type":741,"value":1331},"Лишние ключи в ",{"type":736,"tag":760,"props":1333,"children":1335},{"className":1334},[],[1336],{"type":741,"value":991},{"type":741,"value":1338},", некорректные проверки",{"type":736,"tag":1286,"props":1340,"children":1341},{},[1342,1348],{"type":736,"tag":760,"props":1343,"children":1345},{"className":1344},[],[1346],{"type":741,"value":1347},"Object.keys()",{"type":741,"value":1349},", строгая проверка собственных свойств",{"type":736,"tag":1259,"props":1351,"children":1352},{},[1353,1358,1363],{"type":736,"tag":1286,"props":1354,"children":1355},{},[1356],{"type":741,"value":1357},"Prototype pollution",{"type":736,"tag":1286,"props":1359,"children":1360},{},[1361],{"type":741,"value":1362},"Внешний ввод влияет на прототипы и проверки",{"type":736,"tag":1286,"props":1364,"children":1365},{},[1366,1368,1374,1375],{"type":741,"value":1367},"Фильтрация ключей, ",{"type":736,"tag":760,"props":1369,"children":1371},{"className":1370},[],[1372],{"type":741,"value":1373},"Object.create(null)",{"type":741,"value":1216},{"type":736,"tag":760,"props":1376,"children":1378},{"className":1377},[],[1379],{"type":741,"value":1127},{"data":1381,"body":1382},{},{"type":733,"children":1383},[1384],{"type":736,"tag":737,"props":1385,"children":1386},{},[1387,1389,1394,1395,1400,1401,1406],{"type":741,"value":1388},"В итоге: опасность записи прямо в прототипы базовых типов (например, ",{"type":736,"tag":760,"props":1390,"children":1392},{"className":1391},[],[1393],{"type":741,"value":773},{"type":741,"value":1216},{"type":736,"tag":760,"props":1396,"children":1398},{"className":1397},[],[1399],{"type":741,"value":765},{"type":741,"value":1216},{"type":736,"tag":760,"props":1402,"children":1404},{"className":1403},[],[1405],{"type":741,"value":854},{"type":741,"value":1407},") заключается в том, что меняется поведение сразу у всех значений данного типа во всей программе, включая сторонние библиотеки и будущие обновления среды. Это приводит к труднообнаружимым ошибкам, конфликтам имён, проблемам совместимости и иногда к уязвимостям, связанным с загрязнением прототипов (prototype pollution).",{"data":1409,"body":1410},{},{"type":733,"children":1411},[1412],{"type":736,"tag":737,"props":1413,"children":1414},{},[1415],{"type":741,"value":40},1775735660398]