diff --git a/JavaScript/4-all/readme.md b/JavaScript/4-all/readme.md
new file mode 100644
index 0000000..f03223d
--- /dev/null
+++ b/JavaScript/4-all/readme.md
@@ -0,0 +1,22 @@
+## Вопросы
+
+- Зачем нужно объявлять константу STATIC_FILE_LENGTH?
+- Как вызвать pathTraversal что бы он был равен true?
+- Можно ли утверждать, чем больше проверок на безопасность тем лучше,
+ или в некоторых случаях они создают уязвимость?
+
+## Упражнения
+
+1. Обработайте ошибки:
+
+- когда файла не найден; ✓
+- когда нет прав на чтение файла или каталога; ✗
+- когда происходит попытка чтения файла из каталога выше. ✗
+
+2. Создайте шаблоны страниц с ошибками в специальном каталоге. ✓
+3. Перепишите те места, которые возможно с использованием `fs.promises`. ✓
+4. Объедините все примеры в один: ✓
+
+- отдача индекса каталога; ✓
+- кеширование; ✓
+- обработка ошибок. ✓
diff --git a/JavaScript/4-all/server.js b/JavaScript/4-all/server.js
new file mode 100644
index 0000000..bdcaf68
--- /dev/null
+++ b/JavaScript/4-all/server.js
@@ -0,0 +1,86 @@
+'use strict';
+
+const http = require('node:http');
+const fs = require('node:fs').promises;
+const path = require('node:path');
+
+const PORT = 8000;
+
+const STATIC_PATH = path.join(process.cwd(), './static');
+
+const MIME_TYPE = {
+ default: 'application/octet-stream',
+ html: 'text/html; charset=UTF-8',
+ js: 'application/javascript; charset=UTF-8',
+ css: 'text/css',
+ png: 'image/png',
+ jpg: 'image/jpeg',
+ ico: 'image/x-icon',
+};
+
+const cache = new Map();
+
+const cacheFile = async (filePath) => {
+ const key = filePath.substring(STATIC_PATH.length).replace(/\\/g, '/');
+ const value = await fs.readFile(filePath);
+ cache.set(key, value);
+};
+
+const cacheDirectory = async (directoryPath) => {
+ const files = await fs.readdir(directoryPath, { withFileTypes: true });
+ for (const file of files) {
+ const filePath = path.join(file.path, file.name);
+ if (file.isDirectory()) cacheDirectory(filePath);
+ else cacheFile(filePath);
+ }
+ const key = directoryPath.substring(STATIC_PATH.length).replace(/\\/g, '/');
+ cache.set(
+ key || '/',
+ files.map((file) => file.name)
+ );
+};
+
+cacheDirectory(STATIC_PATH);
+
+const folderIndex = (url) => {
+ const items = cache.get(url);
+ if (url !== '/' && items[0] !== '../') items.unshift('../');
+ const list = items
+ .map((el) => {
+ const addres = path.join(url, el);
+ return `
${el}`;
+ })
+ .join('\n');
+ const file = `Directory files: `;
+ return file;
+};
+
+const prepareFile = (url) => {
+ const filePath = path.join(STATIC_PATH, url);
+ const pathTraversal = !filePath.startsWith(STATIC_PATH);
+ // console.log(pathTraversal)
+ const exists = cache.get(url);
+ const found = !pathTraversal && !!exists;
+ let cachePath = url;
+ if (!found) cachePath = '/errors/404.html';
+ if (pathTraversal) cachePath = '/errors/traversal.html'; // Не знаю как установить true через браузер
+ if (!'readingRights') cachePath = '/errors/no-reading.html'; // Не представляю как это раелизовать без авторизации пользователя
+ const errorPath =
+ cachePath.startsWith('/errors/') && cachePath.endsWith('.html');
+ const isDirectory = exists instanceof Array && !errorPath;
+ const ext = path.extname(cachePath).substring(1);
+ const content = isDirectory ? folderIndex(cachePath) : cache.get(cachePath);
+ return { found, ext: isDirectory ? 'html' : ext, content };
+};
+
+http
+ .createServer((req, res) => {
+ const file = prepareFile(req.url);
+ const mimeType = MIME_TYPE[file.ext] || MIME_TYPE.default;
+ const statusCode = file.found ? 200 : 404;
+ res.writeHead(statusCode, { 'content-type': mimeType });
+ res.end(file.content);
+ })
+ .listen(PORT, () =>
+ console.log(`Server is running: http://localhost:${PORT}`)
+ );
diff --git a/JavaScript/4-all/static/errors/404.html b/JavaScript/4-all/static/errors/404.html
new file mode 100644
index 0000000..0c50a11
--- /dev/null
+++ b/JavaScript/4-all/static/errors/404.html
@@ -0,0 +1 @@
+file is not exists!
diff --git a/JavaScript/4-all/static/errors/no-reading.html b/JavaScript/4-all/static/errors/no-reading.html
new file mode 100644
index 0000000..4a4f630
--- /dev/null
+++ b/JavaScript/4-all/static/errors/no-reading.html
@@ -0,0 +1 @@
+You do not have permission to read this directory!
diff --git a/JavaScript/4-all/static/errors/traversal.html b/JavaScript/4-all/static/errors/traversal.html
new file mode 100644
index 0000000..0b64017
--- /dev/null
+++ b/JavaScript/4-all/static/errors/traversal.html
@@ -0,0 +1 @@
+Occurrd traversal path!
diff --git a/JavaScript/4-all/static/favicon.ico b/JavaScript/4-all/static/favicon.ico
new file mode 100644
index 0000000..e69de29
diff --git a/JavaScript/4-all/static/favicon.png b/JavaScript/4-all/static/favicon.png
new file mode 100644
index 0000000..e69de29
diff --git a/JavaScript/4-all/static/images/Diophant.png b/JavaScript/4-all/static/images/Diophant.png
new file mode 100644
index 0000000..4f75ad5
Binary files /dev/null and b/JavaScript/4-all/static/images/Diophant.png differ
diff --git a/JavaScript/4-all/static/images/channel-xyz.jpg b/JavaScript/4-all/static/images/channel-xyz.jpg
new file mode 100644
index 0000000..08eaa52
Binary files /dev/null and b/JavaScript/4-all/static/images/channel-xyz.jpg differ
diff --git a/JavaScript/4-all/static/index.html b/JavaScript/4-all/static/index.html
new file mode 100644
index 0000000..3e7d6ca
--- /dev/null
+++ b/JavaScript/4-all/static/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+ Document
+
+
+
+
+
+
diff --git a/JavaScript/4-all/static/js/init.js b/JavaScript/4-all/static/js/init.js
new file mode 100644
index 0000000..e921523
--- /dev/null
+++ b/JavaScript/4-all/static/js/init.js
@@ -0,0 +1 @@
+console.log('hello');
diff --git a/JavaScript/4-all/static/styles/style.css b/JavaScript/4-all/static/styles/style.css
new file mode 100644
index 0000000..a6020bf
--- /dev/null
+++ b/JavaScript/4-all/static/styles/style.css
@@ -0,0 +1,6 @@
+.hello {
+ background-color: black;
+ width: 200;
+ height: 60;
+ color: white;
+}