diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml
new file mode 100644
index 0000000..a78957c
--- /dev/null
+++ b/.idea/jsLibraryMappings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..eabe228
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..0a1241c
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/part-1-task-3.iml b/.idea/part-1-task-3.iml
new file mode 100644
index 0000000..24643cc
--- /dev/null
+++ b/.idea/part-1-task-3.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/watcherTasks.xml b/.idea/watcherTasks.xml
new file mode 100644
index 0000000..9338ba6
--- /dev/null
+++ b/.idea/watcherTasks.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..0077e1a
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,585 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ DEFINITION_ORDER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ project
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ project
+
+
+ true
+
+
+
+ DIRECTORY
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1476611106297
+
+
+ 1476611106297
+
+
+
+
+
+ 1476623988209
+
+
+
+ 1476623988209
+
+
+ 1476624544258
+
+
+
+ 1476624544258
+
+
+ 1476638072104
+
+
+
+ 1476638072104
+
+
+ 1476644622372
+
+
+
+ 1476644622372
+
+
+ 1476651839623
+
+
+
+ 1476651839623
+
+
+ 1476655805685
+
+
+
+ 1476655805685
+
+
+ 1476661035060
+
+
+
+ 1476661035060
+
+
+ 1476661382488
+
+
+
+ 1476661382488
+
+
+ 1476798131584
+
+
+
+ 1476798131584
+
+
+ 1476798680520
+
+
+
+ 1476798680520
+
+
+ 1476798863390
+
+
+
+ 1476798863390
+
+
+ 1477510805212
+
+
+
+ 1477510805212
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/index.js b/index.js
index c79da1a..9d6e2bd 100644
--- a/index.js
+++ b/index.js
@@ -2,6 +2,11 @@
const express = require('express');
const app = express();
+const fs = require('fs');
+const path = require('path');
+const Transliterator = require('./transliterator');
+
+//---------------Server Part-------------
const PORT = process.env.PORT || 4000;
@@ -9,5 +14,109 @@ app.listen(PORT, function () {
console.log(`App is listen on ${PORT}`);
});
+//Set timer middleware
+app.use(function (req, res, next) {
+ req.timer = process.hrtime();
+ next();
+});
+
+//---------Middle-wares----------------
+
+//Request url middle-ware
+app.use(function (req, res, next) {
+ let reqUrl = req.method + ' ' + req.url;
+ res.set('X-Request-Url', reqUrl);
+ console.log(reqUrl);
+ next();
+});
+
+//Cookie parser middleware
+app.use(function (req, res, next) {
+ req.cookies = {};
+ let array = [];
+ if (req.headers.cookie) {
+ array = req.headers.cookie.replace('; ', ';').split(';');
+ }
+ for (let i = 0; i < array.length; i++) {
+ let cookie = array[i].split('=');
+ req.cookies[cookie[0]] = cookie[1];
+ }
+ next();
+});
+
+//Check auth middleware
+app.use(function (req, res, next) {
+ if (!req.cookies.authorize) {
+ throw {
+ status: 403,
+ message: 'User unauthorized'
+ };
+ }
+ next();
+});
+
+app.get('/', function (req, res) {
+ throw {
+ status: 503,
+ message: 'Unknown request'
+ }
+});
+
+//------------Log Timer-------------
+
+//Set timer middleware
+app.use(function (req, res, next) {
+ let time = process.hrtime(req.timer);
+ let formatTime = Number(time[0] + '.' + time[1]).toFixed(3);
+ res.set('X-Time', formatTime);
+ console.log(formatTime);
+ next();
+});
+
+//-----------Routes-----------------
+
+app.get('/v1/*', function (req, res) {
+ let rawurl = __dirname + req.url.replace('/v1', '');
+ let url = path.normalize(rawurl);
+ if (url.indexOf(__dirname) === -1) {
+ throw {
+ status: 400,
+ message: 'Wrong path'
+ }
+ }
+ if (fs.lstatSync(url).isDirectory()) {
+ fs.readdir(url, function (err, files) {
+ if (err) throw err;
+ let result = ['.', '..'];
+ res.status(200).send({content: result.concat(files)});
+ });
+ } else {
+ res.set('Content-type', 'application/json');
+ let rstream = fs.createReadStream(url);
+ let tstream = new Transliterator();
+ rstream
+ .pipe(tstream)
+ .pipe(res);
+ }
+});
+
+//-----------Error Handler----------
+
+app.use(function (err, req, res, next) {
+ if (err) {
+ res.set('X-Request-Error', err.message);
+ res.status(err.status).send(err.message);
+ }
+});
+
+app.use(function (req, res, next) {
+ let err = {
+ status: 404,
+ message: 'Unknown request'
+ };
+ res.set('X-Request-Error', err.message);
+ res.status(err.status).send(err.message);
+});
+
// IMPORTANT. Это строка должна возвращать инстанс сервера
-module.exports = app;
+module.exports = app;
\ No newline at end of file
diff --git a/tester b/tester
new file mode 100644
index 0000000..9daeafb
--- /dev/null
+++ b/tester
@@ -0,0 +1 @@
+test
diff --git a/transliterator.js b/transliterator.js
new file mode 100644
index 0000000..ae01255
--- /dev/null
+++ b/transliterator.js
@@ -0,0 +1,110 @@
+const Transform = require('stream').Transform;
+
+const rus = {
+ 'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'Jo',
+ 'Ж': 'Zh', 'З': 'Z', 'И': 'I', 'Й': 'J', 'К': 'K', 'Л': 'L', 'М': 'M',
+ 'Н': 'N', 'О': 'O', 'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'У': 'U',
+ 'Ф': 'F', 'Х': 'H', 'Ц': 'C', 'Ч': 'Ch', 'Ш': 'Sh', 'Щ': 'Shh',
+ 'Ъ': '#', 'Ы': 'Y', 'Ь': '\'', 'Э': 'Je', 'Ю': 'Ju', 'Я': 'Ja'
+};
+
+(function () {
+ for (let key in rus) {
+ rus[key.toLowerCase()] = rus[key].toLowerCase();
+ }
+})();
+
+const en = {
+ 'A': 'А', 'B': 'Б', 'C': 'Ц', 'D': 'Д', 'E': 'Е', 'F': 'Ф',
+ 'G': 'Г', 'H': 'Х', 'I': 'И', 'J': 'Й', 'K': 'К', 'L': 'Л',
+ 'M': 'М', 'N': 'Н', 'O': 'О', 'P': 'П', 'Q': 'Я', 'R': 'Р',
+ 'S': 'С', 'T': 'Т', 'U': 'У', 'V': 'В', 'W': 'Щ', 'X': 'Х',
+ 'Y': 'Ы', 'Z': 'З', '\'': 'ь', '#': 'ъ'
+};
+
+const enSpecial = {
+ 'Jo': 'Ё', 'Yo': 'Ё', 'Ju': 'Ю', 'Yu': 'Ю', 'Ja': 'Я', 'Ya': 'Я',
+ 'Je': 'Э', 'Sh': 'Ш', 'Zh': 'Ж', 'Ch': 'Ч'
+};
+
+const enShh = ['shh', 'Shh', 'SHh', 'SHH', 'ShH'];
+
+(function () {
+ for (let key in enSpecial) {
+ enSpecial[key.toLowerCase()] = enSpecial[key].toLowerCase();
+ enSpecial[key.toUpperCase()] = enSpecial[key].toUpperCase();
+ }
+})();
+
+(function () {
+ for (let key in en) {
+ en[key.toLowerCase()] = en[key].toLowerCase();
+ }
+})();
+
+class Transliterator extends Transform {
+ constructor(options, lang) {
+ super(options);
+ if (lang === 'en') {
+ this.dictionary = en;
+ this.dictionaryName = 'en';
+ } else if (lang === 'rus') {
+ this.dictionary = rus;
+ this.dictionaryName = 'rus';
+ }
+ this._alreadyBeg = false;
+ this._alreadyEnd = false;
+ }
+
+ _transform(chunk, encoding, callback) {
+ let str = chunk.toString('utf8');
+ let formatted = '';
+ if (!this._alreadyBeg) {
+ this.push('{"content": "');
+ }
+ for (let i = 0; i < str.length; i++) {
+ if (!this.dictionary) {
+ if (str[i] in rus) {
+ this.dictionary = rus;
+ this.dictionaryName = 'rus';
+ } else if (str[i] in en) {
+ this.dictionary = en;
+ this.dictionaryName = 'en';
+ }
+ }
+ if (this.dictionaryName === 'en') {
+ if ((i < str.length - 2) && (enShh.indexOf(str[i] + str[i + 1] + str[i + 2]) !== -1)) {
+ formatted += (str[i] === 's') ? 'щ' : 'Щ';
+ i += 2;
+ } else {
+ if ((i < str.length - 1) && ((str[i] + str[i + 1]) in enSpecial)) {
+ formatted += enSpecial[str[i] + str[i + 1]];
+ i += 1;
+ } else {
+ if (str[i] in this.dictionary) {
+ formatted += this.dictionary[str[i]];
+ } else {
+ formatted += str[i];
+ }
+ }
+ }
+ } else if (this.dictionary && str[i] in this.dictionary) {
+ formatted += this.dictionary[str[i]];
+ } else {
+ formatted += str[i];
+ }
+ }
+ this.push(formatted.replace(/"/g, '\"'));
+ callback();
+ }
+
+ _flush(callback) {
+ if (! this._alreadyEnd) {
+ this.push('"}');
+ }
+
+ callback();
+ }
+}
+
+module.exports = Transliterator;
\ No newline at end of file