среда, 5 сентября 2018 г.

Stacktrace function - Custom stack trace in JavaScript



function stacktrace () {
        var stacktraceData = getStacktraceData(arguments.callee.caller);
    function getStacktraceData (functionThatCalledThisStacktraceFunction) {
        if (functionThatCalledThisStacktraceFunction) {
            return (
                   getStacktraceData(functionThatCalledThisStacktraceFunction.caller)
                + functionThatCalledThisStacktraceFunction.toString().split('(')[0].substring(9) // Function name
                + '('
                + Array.prototype.slice.call(functionThatCalledThisStacktraceFunction.arguments).join(', ') // Function arguments
                + ')'
                + '\n'
            );
        } else {
            return '';
        }
    }
    return stacktraceData;
}

main();

function main () {
    var x = execute();
    var y = add(2, 3);
}

function execute () {
    calc();
}

function calc () {
    return add(8, 11) + add(9, 14);
}

function add (x, y) {
    console.log(stacktrace());
    return x + y;
}

среда, 6 июня 2018 г.

NPM Cheat Sheet

# NPM CheatSheet.
# NPM поставляется вместе с Node.js.
# Инструкция по созданию своего npm package: https://www.npmjs.org/doc/misc/npm-developers.html
# Больше информации на: https://www.npmjs.org/doc/


# 1. NPM Команды для командного терминала.
# Локальный режим включен по умолчанию.
# Используйте --global или -g для выполнения команды в глобальном режиме.


npm <cmd> -h                                            # быстрая подсказка по команде <cmd>
npm -l                                                  # вывести список всех команд NPM с их описанием
npm adduser                                             # добавить нового пользователя реестра
npm bin                                                 # показать местонахождение папки .bin
npm bugs <pkgname>                                      # загрузить в браузере страницу с описанием багов указанной библиотеки
npm build <package-folder>                              # собрать библиотеку (не должно вызываться напрямую)
npm cache [add|ls|clean] <tarball|folder>               # работа с кэшем установленных библиотек
npm config [set|get|delete|list|edit] <key> <value>     #управление конфигурационным файлом
npm dedupe [package names...]  --tag                    # уменьшить дублирование установленных библиотек
npm depcrecate <name>[@<version>] <message>              # пометить версию библиотеки, как устаревшую (для этого вы должны быть владельцем данной библиотеки)
npm docs [<pkg-name> [<pkg-name> ...]]                  # открыть страницу с документацией по библиотеке в браузере
npm edit <name>[@<version>]                             # отредактировать установленную библиотеку (по умолчанию будет использован редактор "vi")
npm explore <name>[@<version>] [ -- <cmd>]              # просмотреть установленную библиотеку
npm faq                                                 # список часто задаваемых вопросов об NPM (аналог help)
npm help-search <some search terms>                     # поиск по документации NPM
npm help <topic> <some search terms>                    # вывести подсказку по NPM
npm init                                                # создать файл package.json
npm install <folder|name@<tag|version>|tarball>         # установить библиотеку из репозитория NPM (необязательные флаги: --save, --save-dev, --save-optional, --save-exact)
npm link <pkgname>                                      # симлинк на папку библиотеки
npm ls <pkg>                                            # вывести список всех установленных библиотек (и их зависимостей)
npm outdated [<name> [<name> ...]]                      # проверить какие библиотеки уже устарели
npm owner [ls|add|rm] <pkg-name> <user>                 # управление владельцами библиотек
npm pack [<pkg> [<pkg> ...]]                            # создать архив tarball из библиотеки
npm prefix                                              # отобразить префикс
npm prune [<name> [<name ...]] --production             # удалить установленные посторонний библиотеки, не перечисленные в файле package.json
npm publish <tarball|folder> [--tag <tag>]              # опубликовать библиотеку в хранилище NPM
npm rebuild [<name > [<name> ...]]                      # пересобрать библиотеку
npm repo <pkgname>                                      # открыть репозиторий библиотеки в браузере
npm restart <name>                                      # запустить библиотеку
npm rm <name>                                           # удалить установленную библиотеку
npm root                                                # отобразить путь до папки node_modules
npm run [<pkg>] [command]                               # запустить команду, описанную в разделе script файла package.json
npm search [search terms ...] [--long]                  # найти библиотеку с таким-то названием в репозитории NPM
npm shrinkwrap                                          # создать файл npm-shrinkwrap.json, в котором перечислены и зафиксированы все установленные библиотеки и их версии. Если это файл присутствует, то инсталляция библиотек будет происходить строго с учетом данных из этого фала.
npm star <pkgname> [<pkg>, ...]                         # пометить любимые библиотеки
npm stars [username]                                    # посмотреть библиотеки отмеченные, как любимые
npm start <name>                                        # выполнить команду start библиотеки
npm stop <name>                                         # выполнить команду stop библиотеки
npm submodule <pkg>                                     # добавить библиотеку в качестве git submodule
npm tag <name>@<version>                                # пометить tag публичную версию библиотеки
npm test <name>                                         # выполнить команду test библиотеки
npm unpublish <name>[@<version>]                        # удалить библиотеку из репозитория NPM
npm unstar <pkgname> [<pkg>, ...]                       # удалить пометку библиотеки, как любимую
npm update [-g] [<name> [<name> ...]]                   # обновить установленную версию библиотеки
npm version [<newversion> | major | minor | patch]      # поднять версию библиотеки
npm view <name>[@<version>] [<field<[.<subfield>] ...]  # показать информацию о библиотеке
npm whoami                       # показать информацию о текущем пользователе


// 2. NPM API документация.
// Перед использованием команд NPM должна быть вызвана функция npm.load().


npm.load(configs, callback);                        // загрузить настройки из кофигурационного файла

npm.commands.bin(args, callback);                   // показать местонахождения папки npm bin
npm.commands.bugs(package, callback);               // открыть в браузере информацию о багах данной библиотеки

npm.commands.cache([args], callback);                           // программное управление npm cache
npm.commands.cache.clean([args], callback);                     // очистка npm cache
npm.commands.cache.add([args], callback);                       // добавление npm cache
npm.commands.cache.read(name, version, forceBypass, callback);  // чтение npm cache

npm.commands[<command>](args, callback);            // выполнить команду NPM

npm.commands.config(args, callback);                // управление конфигурационным файлом NPM
npm.config.get(key);                                // получить установленное значение конфига по ключу
npm.config.set(key, value);                         // установить значение конфига по ключу

npm.commands.deprecate(args, callback);             // пометить версию библиотеки, как устаревшую
npm.commands.docs(package, callback);               // открыть страницу с документацией библиотеки в браузере
npm.commands.edit(package, callback);               // отредактировать установленную библиотеку
npm.commands.explore(args, callback);               // просмотреть библиотеку
npm.commands.helpSearch(args, [silent,] callback);  // поиск по подсказкам в документации NPM
npm.commands.init(args, callback);                  // создать файл package.json
npm.commands.install([where,] packages, callback);  // установить библиотеку
npm.commands.link([packages,] callback);            // создать симлинк на папку библиотеки
npm.commands.ls(args, [silent,] callback);          // показать список всех установленных библиотек
npm.commands.outdated([packages,] callback);        // проверить не устарели ли библиотеки
npm.commands.owner(args, callback);                 // управление владельцами библиотек
npm.commands.pack([packages,] callback);            // создать архив tarball из папки билиотеки
npm.commands.prefix(args, callback);                // показать префикс
npm.commands.prune([packages,] callback);           // удалить установленные посторонний библиотеки, не перечисленные в файле package.json
npm.commands.publish([packages,] callback);         // опубликовать библиотеку в репозиторий NPM
npm.commands.rebuild([packages,] callback);         // пересобрать библиотеку
npm.commands.repo(package, callback);               // открыть страницу с репозиторием библиотеки в браузере
npm.commands.restart(packages, callback);           // выполнить команду start библиотеки
npm.commands.root(args, callback);                  // отобразить путь до папки node_modules
npm.commands.run-script(args, callback);            // выполнить команду из разделе script файла package.json

npm.commands.search(searchTerms, [silent,] [staleness,] callback);  // найти библиотеку в репозитории NPM

npm.commands.shrinkwrap(args, [silent,] callback);  // создать файл npm-shrinkwrap.json, в котором перечислены и зафиксированы все установленные библиотеки и их версии. Если это файл присутствует, то инсталляция библиотек будет происходить строго с учетом данных из этого фала.
npm.commands.start(packages, callback);             // выполнить команду start библиотеки
npm.commands.stop(packages, callback);              // выполнить команду stop библиотеки
npm.commands.submodule(packages, callback);         // добавить библиотеку в качестве git submodule
npm.commands.tag(package@version, tag, callback);   // пометить tag публичную версию библиотеки
npm.commands.test(packages, callback);              // выполнить команду test библиотеки
npm.commands.uninstall(packages, callback);         // удалить установленную  библиотеку
npm.commands.unpublish(package, callback);          // удалить библиотеку из репозитория NPM
npm.commands.update(packages, callback);            // обновить установленную версию библиотеки
npm.commands.version(newversion, callback);         // поднять версию библиотеки
npm.commands.view(args, [silent,] callback);        // показать информацию о библиотеке
npm.commands.whoami(args, callback);                // показать информацию о текущем пользователе


// 3. Содержимое файла package.json

{
  "name": "module-name",
  "version": "10.5.2",
  "description": "An example module to illustrate the usage of a package.json",
  "keywords": ["nodejitsu", "example", "browsenpm"],
  "license": "MIT",
  "author": "Your Name <you.name@example.org>",
  "contributors": [{
      "name": "Foo Bar",
       "email": "foo.bar@example.com"
  }],
  "publishConfig": {
    "registry": "https://your-private-hosted-npm.registry.nodejitsu.com"
  },
  "repository": {
      "type": "git",
      "url": "https://github.com/nodejitsu/browsenpm.org"
   },
  "bugs": {
      "url": "https://github.com/nodejitsu/browsenpm.org/issues"
   },
  "preferGlobal": true,
  "private": true,
  "analyze": true,
  "subdomain": "foobar",
  "bin": {
      "module-name": "./bin/module-name"
  },
  "main": "lib/foo.js",
  "script": {
      "test": "vows --spec --isolate",
      "start": "node index.js",
      "predeploy": "echo i am about to deploy",
      "postdeploy": "echo i have deployed",
      "prepublish": "coffee --bare --compile --output lib/foo src/foo/*.coffee"
  },
  "dependencies": {
      "primus": "*",
      "async": "~0.8.0",
      "express": "4.2.x",
      "winston": "git://github.com/flatiron/winston#master",
      "bigpipe": "bigpipe/pagelet",
      "plates": "https://github.com/flatiron/plates/tarball/master"
  },
  "devDependencies": {
      "vows": "^0.7.0",
      "assume": "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0",
      "pre-commit": "*"
  }
}

Node.js Quick CheatSheet

/* *******************************************************************************************
 * Краткий обзор
 * http://nodejs.org/api/synopsis.html
 * ******************************************************************************************* */


var http = require('http');

// Пример сервера, оправляющего в браузер ответ 'Hello World'.
// Для запуска сервера поместите код в файл с именем example.js и выполните его с помощью Node.js.

http.createServer(function (request, response) {
  response.writeHead(200, {'Content-Type': 'text/plain'});
  response.end('Hello World');
}).listen(8000);

console.log('Сервер запущен по адресу http://127.0.0.1:8000/');


/* *******************************************************************************************
 * Глобальные объекты
 * http://nodejs.org/api/globals.html
 * ******************************************************************************************* */


__filename;  // Абсолютный путь до файла, код которого выполняется.
__dirname;   // Абсолютный путь до директории, в которой находится файл с выполняемым кодом.
module;      // Ссылка на текущий модуль. В частности module.exports используется для определения того, что модуль экспортирует и делает доступным для загрузки через require().
exports;     // Укороченная ссылка на module.exports.
process;     // Глобальный объект текущего запущенного процесса Node.js. Доступен везде. Является экземпляром класса EventEmitter.
Buffer;      // Глобальный класс для работы напрямую с двоичными данными.


/* *******************************************************************************************
 * Консоль
 * http://nodejs.org/api/console.html
 * ******************************************************************************************* */


console.log([data], [...]);             // Печатает текст вместе с символом перевода на новую строку на конце в stdout командного терминала.
console.info([data], [...]);            // Тоже самое, что и console.log.
console.error([data], [...]);           // Тоже самое, что и console.log, но печатает текст в stderr командного терминала.
console.warn([data], [...]);            // Тоже самое, что и console.error.
console.dir(obj);                       // Использует util.inspect на obj и печатает итоговую строку с текстом в stdout командного терминала.
console.time(label);                    // Запускает замер времени.
console.timeEnd(label);                 // Останавливает замер времени и выводит итоговое время в stdout командного терминала.
console.trace(label);                   // Печатает содержимое стека (stack trace) в данный момент в stderr командного терминала.
console.assert(expression, [message]);  // Тоже самое, что и assert.ok(), в котором, если выполняемое выражение получает в итоге значение false, то выбрасывается исключение AssertionError с соответствующим сообщением.


/* *******************************************************************************************
 * Таймеры
 * http://nodejs.org/api/timers.html
 * ******************************************************************************************* */


setTimeout(callback, delay, [arg], [...]);   // Выполняет функцию callback один раз через указанное число миллисекунд. В функцию callback также можно передать указанные аргументы.
clearTimeout(t);                             // Отменяет выполнение ранее созданного таймера с помощью функции setTimeout().
setInterval(callback, delay, [arg], [...]);  // Повторно выполняет функцию callback через заданное число миллисекунд до тех пор, пока не будет отменено с помощью функции clearInterval(). В функцию callback также можно передать указанные аргументы.
clearInterval(t);                            // Отменяет выполнение ранее созданного таймера с помощью функции setInterval().
setImmediate(callback, [arg], [...]);        // Немедленно выполняет функцию callback после выполнения всех операций ввода-вывода и до setTimeout и setInterval.
clearImmediate(immediateObject);             // Отменяет выполнение ранее созданного таймера с помощью функции setImmediate().

unref();  // Позволяет создавать таймер, который будет активен только до того момента, пока программа Node.js выполняется и есть активные элементы в цикле event loop. После завершения всех операций в цикле event loop программа будет закрыта.
ref();    // Если вы ранее выполнили функцию unref() для таймера, то вы можете выполнить функцию ref(), которая позволит таймеру удерживать вашу программу от закрытия после того, как все операции в цикле event loop будут завершены.


/* *******************************************************************************************
 * Модули
 * http://nodejs.org/api/modules.html
 * ******************************************************************************************* */


var module = require('./file.js');    // Загружает модуль file.js, находящийся в той же директории.
module.require('./another_file.js');  // Загружает модуль another_file.js так, как если бы функция  require() была вызвана самим модулем.

module.id;        // Идентификатор модуля. Обычно это путь до файла.
module.filename;  // Абсолютный путь до файла с его именем.
module.loaded;    // Загружен ли уже модуль или он всё ещё загружается.
module.parent;    // Родительский модуль, который загрузил данный модуль.
module.children;  // Дочерние модули, которые загрузил данный модуль через функцию require().

// Экспорт из модуля функции с именем area.
exports.area = function (r) {
  return Math.PI * r * r;
};

// module.exports - это объект с перечнем экспортируемых из данного модуля элементов.
// Если вы хотите, то можете превратить его в функцию, например функцию-конструктор, которая будет создавать экспортируемые объекты или вы можете присвоить ему экспортируемый объект, в котором находятся все экспортируемые элементы сразу.
// Присвоение значения module.exports затирает значения в exports.
module.exports = function(width) {
  return {
    area: function() {
      return width * width;
    }
  };
}


/* *******************************************************************************************
 * Процесс
 * http://nodejs.org/api/process.html
 * ******************************************************************************************* */


process.on('exit', function(code) {});              // Функция вызывается, когда процесс Node.js завершается и происходит выход из программы.
process.on('uncaughtException', function(err) {});  // Функция вызывается, когда появляется никем не перехваченное исключение. В этом случае программа не вылетает и продолжает работать выполняться со сбоем, поэтому не стоит эту функцию использовать.

process.stdout;           // Поток для записи в stdout командного терминала.
process.stderr;           // Поток для записи в  stderr командного терминала.
process.stdin;            // Поток чтения из stdin командного терминала.

process.argv;             // Массив, содержащий все аргументы, переданные из командной строки терминала во время запуска программы.
process.env;              // Объект, содержащий значения переменных среды окружения (например значение переменной среды Path из Windows).
process.execPath;         // Абсолютный путь до файла node.exe, который запустил данную JavaSctipt-программу.
process.execArgv;         // Массив, содержащий все аргументы командных опций Node.js, которые были введены при запуске программы.

process.arch;             // Архитектура процессора системы: 'arm', 'ia32', 'x64'.
process.config;           // Объект, содержащий в себе конфигурационные опции, которые были использованы для компиляции и создания текущего файла node.exe.
process.pid;              // Идентификатор текущего запущенного процесса PID .
process.platform;         // Операционная система, в которой запущена данная программа: 'darwin', 'freebsd', 'linux', 'sunos', 'win32'.
process.title;            // Getter/setter для установки имени процесса для отображения в 'ps'. (Например C:\\WINDOWS\\system32\\cmd.exe - node)
process.version;          // Версия Node.js.
process.versions;         // Версия Node.js и некоторых его внутренних модулей.

process.abort();          // Прервать выполнение программы. Это заставит Node.js выйти из программы и сгенерировать core file.
process.chdir(dir);       // Изменить текущую рабочую директорию, из которой была запущена программа. Выбрасывает исключение, если изменить текущую рабочую директорию невозможно.
process.cwd();            // Текущая рабочая директория, из которой была запущена программа.
process.exit([code]);     // Завершить программу с заданным кодом. Если код не задан, то программ успешно завершится с кодом 0.
process.getgid();         // Получить идентификатор группы пользователей данного процесса.
process.setgid(id);       // Установить идентификатор группы пользователей данного процесса.
process.getuid();         // Получить идентификатор пользователя данного процесса.
process.setuid(id);       // Установить идентификатор пользователя данного процесса.
process.getgroups();      // Получить массив с идентификаторами дополнительных групп пользователей.
process.setgroups(grps);  // Установить идентификаторы дополнительных групп пользователей.

process.initgroups(user, extra_grp);  // Читает содержимое /etc/group и инициализирует лист доступа для группы, использую группы, к которых данный пользователь является их членом.
process.kill(pid, [signal]);          // Посылает сигнал signal процессу с идентификатором pid.
process.memoryUsage();                // Возвращает объект, описывающий использование памяти данным процессом Node.js в байтах.
process.nextTick(callback);           // Вызвать функцию callback на следующем шаге цикла event loop.
process.maxTickDepth;                 // Обратные вызовы, переданные процессу .nextTick обычно вызывается в конце текущего потока выполнения и, таким образом, примерно так же быстро, как вызов функции синхронно.
process.umask([mask]);                // Устанавливает или считывает маску создания процесса файла.
process.uptime();                     // Время выполнения данной программы в секундах.
process.hrtime();                     // Текущее время в высоком разрешении в формате массива [seconds, nanoseconds] (удобно для точного замера времени выполнения какой-либо функции).


/* *******************************************************************************************
 * Дочерний процесс
 * http://nodejs.org/api/child_process.html
 * ******************************************************************************************* */

// Дочерний процесс - это отдельная Node.js программа, запускаемая из родительской Node.js программы.

ChildProcess;                                                 // Класс. ChildProcess является EventEmitter.

child.stdin;                                                  // Поток ввода дочернего процесса stdin.
child.stdout;                                                 // Поток вывода дочернего процесса stdout.
child.stderr;                                                 // Поток вывода ошибок дочернего процесса stderr.
child.pid;                                                    // Идентификатор дочернего процесса PID.
child.connected;                                              // Если .connected равно false, то больше невозможно посылать сообщения в дочерний процесс из родительского процесса.
child.kill([signal]);                                         // Послать сигнал signal в дочерний процесс.
child.send(message, [sendHandle]);                            // После создания дочернего процесса с помощью функции child_process.fork() вы можете отправлять в дочерний процесс данные с помощью функции child.send(message, [sendHandle]) и получать их в дочернем процессе с помощью события .on('message', callback).
child.disconnect();                                           // Закрыть канал передачи данных IPC между родительским и дочерним процессом. channel between parent and child, что позволяет дочернему процессу завершить своё выполнение, поскольку больше никаких соединений с ним не установлено.

child_process.spawn(command, [args], [options]);              // Запускает дочерний процесс с переданными в него аргументами. Передача данных в дочерний процесс или из него осуществляется через потоки streams.
child_process.exec(command, [options], callback);             // Выполняет команду в командном терминале и возвращает результат её выполнения.
child_process.execFile(file, [args], [options], [callback]);  // Выполняет файл в командном терминале и возвращает результат его выполнения.
child_process.fork(modulePath, [args], [options]);            // Особая форма функции spawn(), которая выполняет JavaScript-файл, как отдельную Node.js программу. Общение между родительской и дочерней программой производится через посылку друг другу сообщений messafe.


/* *******************************************************************************************
 * Утилиты
 * http://nodejs.org/api/util.html
 * ******************************************************************************************* */


// Эти функции содержатся в модуле 'util'. Используйте require('util') для получения доступа к ним.

util.format(format, [...]);    // Возвращает отформатированную строку. Символы для подстановки строкиЮ числа и данных в формате JSON: %s, %d, %j
util.debug(string);            // Функция для синхронного вывода текста в stderr командного терминала.
util.error([...]);             // Тоже самое. что и util.debug(), но только выводит все аргументы stderr командного терминала.
util.puts([...]);              // Функция для синхронного вывода текста в stdout командного терминала с символом новой строки после каждого аргумента.
util.print([...]);             // Функция для синхронного вывода текста в stdout командного терминала без символов новой строки после каждого аргумента.
util.log(string);              // Выводит текст вместе с временной меткой в stdout командного терминала.
util.inspect(object, [opts]);  // Выводит объект в виде строки, что удобно для поиска багов. (Опции: showHidden, depth, colors, customInspect)
util.isArray(object);          // Возвращает true, если переданный объект является массивом и false, если нет.
util.isRegExp(object);         // Возвращает true, если переданный объект является регулярным выражением и false, если нет.
util.isDate(object);           // Возвращает true, если переданный объект является датой и false, если нет.
util.isError(object);          // Возвращает true, если переданный объект является объектом Error и false, если нет.
util.promisify(fn);             // Берет функцию, в которой последний аргумент является callback-функцией и превращает её в функцию, возвращающую promise.

util.inherits(constructor, superConstructor);  // Копирует методы прототипа из одной функции конструктора в другую функцию конструктор.


/* *******************************************************************************************
 * События
 * http://nodejs.org/api/events.html
 * ******************************************************************************************* */


// Для доступа к классу EventEmitter необходимо сделать импорт require('events').EventEmitter.
// Все классы типа EventEmitters вызывают событие 'newListener' при создании нового слушателя событий и вызывают событие 'removeListener' при удаления слушателя событий.

emitter.addListener(event, listener);        // Добавляет новый слушатель событий в конец массива слушателей событий данного типа события.
emitter.on(event, listener);                 // Тоже самое, что и emitter.addListener().
emitter.once(event, listener);               // Добавляет новый слушатель данного типа события. Как только данное событие будет вызвано этот слушатель события будет удален.
emitter.removeListener(event, listener);     // Удаляет слушатель данного типа событий из массива слушателей событий.
emitter.removeAllListeners([event]);         // Удаляет все слушатели события данного типа из массива слушателей событий.
emitter.setMaxListeners(n);                  // Устанавливает максимальное число слушателей события данного типа, которых можно добавить. Добавление слушателя события сверх этого числа вызовет ошибку.
emitter.listeners(event);                    // Возвращает массив функций слушателей события данного типа.
emitter.emit(event, [arg1], [arg2], [...]);  // Вызывает все слушатели событий данного типа в порядке их добавления с передачей в них прописанных аргументов. Возвращает true, если у данного типа события есть слушатели и false, если нет.

EventEmitter.listenerCount(emitter, event);  // Возвращает число созданных слушателей события данного типа.


/* *******************************************************************************************
 * Потоки
 * http://nodejs.org/api/stream.html
 * ******************************************************************************************* */


// Потоки бывают для чтения, для записи и двунаправленные потоки. Все потоки являются экземплярами EventEventEmitter.

// Поток для чтения считывает данные порциями. Он не начнет работать пока вы не укажете начать читать данные.
// Примеры потока для чтения: http responses on the client, http requests on the server, fs read streams, zlib streams, crypto streams, tcp sockets, child process stdout and stderr, process.stdin.

var readable = getReadableStreamSomehow();

readable.on('readable', function() {});   // Вызывается, когда часть данных готова для чтения.
readable.on('data', function(chunk) {});  // Добавление этого слушателя событий переведет поток чтения в автоматический потоковый режим, в котором данные будут автоматически читаться по мере их готовности для чтения.
readable.on('end', function() {});        // Вызывается, когда нет больше данных для чтения.
readable.on('close', function() {});      // Вызывается, когда ресурс для чтения будет закрыт (например будет закрыт открытый файл). Не все потоки излучают подобное событие.
readable.on('error', function() {});      // Вызывается, если произошла ошибка при получении данных для чтения.

// Метод read() вытаскивает данные из внутреннего буфера и передает их потоку чтения. Если в во внутреннем буфере больше нет данных, то он возвращает null.
// Данный метод можно вызывать только в ручном режиме чтения. В автоматическом потоковом режиме чтения этот метод вызывается автоматически до тех пор пока внутренний буфер не опустеет.
readable.read([size]);

readable.setEncoding(encoding);           // Заставляет поток возвращать строки в заданной кодировке вместо объектов вида Buffer.
readable.pause();                         // Этот метод останавливает автоматический поток чтения и переводит его в ручной пошаговый режим чтения.
readable.resume();                        // Этот метод восстанавливает автоматический поток чтения и переводит его из ручной пошагового режима чтения в автоматический.
readable.pipe(destination, [options]);    // Этот метод автоматически вытаскивает данные из потока чтения и передаёт их в поток записи.
readable.unpipe([destination]);           // Этот метод отменяет действие ранее вызванной функции pipe(). Если destination не задано, то отменяются все ранее созданные функции pipe().
readable.unshift(chunk);                  // Эта функция полезна в некоторых случаях, когда поток потребляется парсером, который должен "не потреблять" некоторые данные, которые он оптимистически вытащил из источника, чтобы поток мог быть передан какой-либо другой стороне.


// Поток для записи записывает данные порциями.
// Примеры потока для записи: http requests on the client, http responses on the server, fs write streams, zlib streams, crypto streams, tcp sockets, child process stdin, process.stdout, process.stderr.

var writer = getWritableStreamSomehow();

writable.write(chunk, [encoding], [callback]);  // Записывает порцию данных и вызывает после этого функцию callback.
writer.once('drain', write);                    // Если функция writable.write(chunk) вернула false, тогда событие drain укажет когда можно начать запись новых данных в потоке.

writable.end([chunk], [encoding], [callback]);  // Вызывается, когда больше не надо записывать данные в потоке записи.
writer.on('finish', function() {});             // Вызывается после того, как будет выполнен метод  end() и все данные будут вычищены из внутренней системы
writer.on('pipe', function(src) {});            // Вызывается, когда к потоку записи будет подключен поток чтения с помощью метода pipe().
writer.on('unpipe', function(src) {});          // Вызывается, когда от потока записи будет отключен поток чтения с помощью метода unpipe().
writer.on('error', function(src) {});           // Вызывается, если в потоке записи произойдет ошибка.


// Дуплексные потоки представляют из себя одновременно поток чтения и поток записи.
// Примеры дуплексных потоков: tcp sockets, zlib streams, crypto streams.

// Трансформирующие потоки - это дуплексные потоки, в которых входящие данные для чтения трансформируются и передаются в поток записи.
// Примеры трансформирующих потоков: zlib streams, crypto streams.


/* *******************************************************************************************
 * Файловая система
 * http://nodejs.org/api/fs.html
 * ******************************************************************************************* */


// Для использования этого модуля сделайте импорт require('fs').
// Все методы здесь имеют асинхронную и синхронную версию.

fs.rename(oldPath, newPath, callback);  // Асинхронное переименование папки или файла, а также их перемещение.
fs.renameSync(oldPath, newPath);        // Синхронное переименование папки или файла, а также их перемещение.

fs.ftruncate(fd, len, callback);        // Асинхронное обрезание содержимого открытого файла с данным fd до заданной длины.
fs.ftruncateSync(fd, len);              // Синхронное обрезание содержимого открытого файла с данным fd до заданной длины.
fs.truncate(path, len, callback);       // Асинхронное обрезание содержимого файла, находящегося по заданному адресу, до заданной длины.
fs.truncateSync(path, len);             // Синхронное обрезание содержимого файла, находящегося по заданному адресу, до заданной длины.

fs.chown(path, uid, gid, callback);     // Асинхронное изменение владельца данного файла, находящегося по заданному адресу.
fs.chownSync(path, uid, gid);           // Синхронное изменение владельца данного файла, находящегося по заданному адресу.
fs.fchown(fd, uid, gid, callback);      // Асинхронное изменение владельца данного открытого файла с данным fd.
fs.fchownSync(fd, uid, gid);            // Синхронное изменение владельца данного открытого файла с данным fd.
fs.lchown(path, uid, gid, callback);    // Асинхронное изменение владельца данного файла, находящегося по заданному адресу.
fs.lchownSync(path, uid, gid);          // Синхронное изменение владельца данного файла, находящегося по заданному адресу.

fs.chmod(path, mode, callback);         // Асинхронное изменение режима чтения, записи и выполнения данного файла, находящегося по заданному адресу.
fs.chmodSync(path, mode);               // Синхронное изменение режима чтения, записи и выполнения данного файла, находящегося по заданному адресу.
fs.fchmod(fd, mode, callback);          // Асинхронное изменение режима чтения, записи и выполнения данного открытого файла с данным fd.
fs.fchmodSync(fd, mode);                // Синхронное изменение режима чтения, записи и выполнения данного открытого файла с данным fd.
fs.lchmod(path, mode, callback);        // Асинхронное изменение режима чтения, записи и выполнения данного файла, находящегося по заданному адресу.
fs.lchmodSync(path, mode);              // Синхронное изменение режима чтения, записи и выполнения данного файла, находящегося по заданному адресу.

fs.stat(path, callback);                // Асинхронное чтение характеристик данного файла, находящегося по заданному адресу. Аргументы (err, stats), где stats является объектом вида fs.Stats.
fs.statSync(path);                      // Синхронное чтение характеристик данного файла, находящегося по заданному адресу.
fs.lstat(path, callback);               // Асинхронное чтение характеристик данного файла, находящегося по заданному адресу. Аргументы (err, stats), где stats является объектом вида fs.Stats. В отличии от stat(), если path является symbolic link, тогда ссылка сам по себе выводится в stat, а не файл, на который она ссылается.
fs.lstatSync(path);                     // Синхронное чтение характеристик данного файла, находящегося по заданному адресу.
fs.fstat(fd, callback);                 // Асинхронное чтение характеристик данного открытого файла с данным fd. Аргументы (err, stats), где stats является объектом вида fs.Stats.
fs.fstatSync(fd);                       // Синхронное чтение характеристик данного открытого файла с данным fd.

fs.link(srcpath, dstpath, callback);             // Асинхронное копирование файла.
fs.linkSync(srcpath, dstpath);                   // Синхронное копирование файла.
fs.symlink(srcpath, dstpath, [type], callback);  // Асинхронное создание символической ссылки файла. Тип может быть: 'dir', 'file', 'junction' (по умолчанию стоит 'file') и доступны только на Windows (другие операционные системы игнорируются).
fs.symlinkSync(srcpath, dstpath, [type]);        // Синхронное создание символической ссылки файла. Тип может быть: 'dir', 'file', 'junction' (по умолчанию стоит 'file') и доступны только на Windows (другие операционные системы игнорируются).
fs.readlink(path, callback);                     // Асинхронное чтение ссылки. callback принимает 2 аргумента (err, linkString).
fs.readlinkSync(path);                           // Синхронное чтение ссылки.
fs.unlink(path, callback);                       // Асинхронное удаление файла.
fs.unlinkSync(path);                             // Синхронное удаление файла.

fs.realpath(path, [cache], callback);     // Асинхронное получение реального пути до файла. callback принимает 2 аргумента (err, resolvedPath).
fs.realpathSync(path, [cache]);           // Синхронное получение реального пути до файла.

fs.rmdir(path, callback);                 // Асинхронное удаление директории.
fs.rmdirSync(path);                       // Синхронное удаление директории.
fs.mkdir(path, [mode], callback);         // Асинхронное создание директории. По умолчанию стоит mode 0777.
fs.mkdirSync(path, [mode]);               // Синхронное создание директории. По умолчанию стоит mode 0777.
fs.readdir(path, callback);               // Асинхронное чтение списка файлов и папок в директории. callback принимает 2 аргумента (err, files), в которых files представляет из себя массив с именами файлов и папок в заданной директории, исключая '.' и '..'.
fs.readdirSync(path);                     // Синхронное чтение списка файлов и папок в директории.
fs.close(fd, callback);                   // Асинхронное закрытие открытого файла заданным fd.
fs.closeSync(fd);                         // Синхронное закрытие открытого файла заданным fd.
fs.open(path, flags, [mode], callback);   // Асинхронное открытие файла, находящегося по заданному пути.
fs.openSync(path, flags, [mode]);         // Синхронное открытие файла, находящегося по заданному пути.
fs.utimes(path, atime, mtime, callback);  // Асинхронное изменение временного штампа файла, находящегося по заданному пути.
fs.utimesSync(path, atime, mtime);        // Синхронное изменение временного штампа файла, находящегося по заданному пути.
fs.futimes(fd, atime, mtime, callback);   // Асинхронное изменение временного штампа открытого файла, с заданным fd.
fs.futimesSync(fd, atime, mtime);         // Синхронное изменение временного штампа открытого файла, с заданным fd.
fs.fsync(fd, callback);                   // Асинхронное fsync.
fs.fsyncSync(fd);                         // Синхронное fsync.

fs.write(fd, buffer, offset, length, position, callback);  // Асинхронно записать двоичные данные в открытый файл с заданным fd.
fs.writeSync(fd, buffer, offset, length, position);        // Синхронно записать двоичные данные в открытый файл с заданным fd.
fs.read(fd, buffer, offset, length, position, callback);   // Асинхронно прочитать двоичные данные в открытом файле с заданным fd.
fs.readSync(fd, buffer, offset, length, position);         // Синхронно прочитать двоичные данные в открытом файле с заданным fd.
fs.readFile(filename, [options], callback);                // Асинхронно прочитать всё содержимое файла сразу. Если задана кодировка, то вернется строка, иначе вернется двоичный буфер с данными.
fs.readFileSync(filename, [options]);                      // Синхронно прочитать всё содержимое файла сразу. Если задана кодировка, то вернется строка, иначе вернется двоичный буфер с данными.

fs.writeFile(filename, data, [options], callback);   // Асинхронно записать данные в файл, полностью замени его, если он уже существует. Данные могу быть строкой или двоичным буфером.
fs.writeFileSync(filename, data, [options]);         // Синхронно записать данные в файл, полностью замени его, если он уже существует. Данные могу быть строкой или двоичным буфером.
fs.appendFile(filename, data, [options], callback);  // Асинхронно дописать данные в конец файла, если он уже существует или создать файл с новыми данными, если он еще не существует. Данные могу быть строкой или двоичным буфером.
fs.appendFileSync(filename, data, [options]);        // Синхронно дописать данные в конец файла, если он уже существует или создать файл с новыми данными, если он еще не существует. Данные могу быть строкой или двоичным буфером.
fs.watch(filename, [options], [listener]);           // Отслеживать событие изменения содержимого файла или директории. Возвращает объект s.FSWatcher. callback слушателя принимает 2 аргумента (event, filename). event может быть или  'rename' или'change', а filename - это имя фала, вызвавшего данное событие.
fs.exists(path, callback);                           // Асинхронно проверить существует ли данный файл и вернуть в функцию callback значение true или false. (не стоит использовать данную функцию)
fs.existsSync(path);                                 // Синхронно проверить существует ли данный файл и вернуть в функцию callback значение true или false. (не стоит использовать данную функцию)

// fs.Stats: объект возвращаемый в функциях fs.stat(), fs.lstat() и fs.fstat() и их синхронных версиях:
stats.isFile();
stats.isDirectory()
stats.isBlockDevice()
stats.isCharacterDevice()
stats.isSymbolicLink()  // (действует только с fs.lstat())
stats.isFIFO()
stats.isSocket()

fs.createReadStream(path, [options]);   // Возвращает новый поток чтения из файла.
fs.createWriteStream(path, [options]);  // Возвращает новый поток записи в файл.


/* *******************************************************************************************
 * Путь
 * http://nodejs.org/api/fs.html
 * ******************************************************************************************* */


// Для использования этого модуля сделайте импорт require('path').
// Этот модуль содержит функции для обработки и трансформации путей к файлам.
// Почти все эти функции просто трансформируют обычные строки.
// Файловая система не проверяется на существование файлов по данным путям.

path.normalize(p);                    // Нормализовать строку с путём. Преобразовать  '..' и '.' в правильные пути.
path.join([path1], [path2], [...]);   // Объединить все части пути в одну строку и нормализовать итоговый путь в строке.
path.resolve([from ...], to);         // Определить полный путь до файлаь.
path.relative(from, to);              // Определить полный путь для перемещения из директории 'from' в директорию 'to'.
path.dirname(p);                      // Вернуть путь до директории для заданного пути.
path.basename(p, [ext]);              // Вернуть имя файла с расширением для заданного пути.
path.extname(p);                      // Вернуть расширение файла для заданного пути.

path.sep;                             // Разделитель в путях файлов для данной операционной системы: '\\' или '/'.
path.delimiter;                       // Разделитель в путях файлов в переменной окружения для данной операционной системы: ';' or ':'.


/* *******************************************************************************************
 * HTTP
 * http://nodejs.org/api/http.html
 * ******************************************************************************************* */


// Для создания HTTP server и client сделайте импорт require('http').

http.STATUS_CODES;                                             // Объект с набором стандартных кодов  HTTP ответов и их текстов.
http.request(options, [callback]);                             // Функция для отправки запроса на сервер.
http.get(options, [callback]);                                 // Функция для мгновенной отправки GET-запроса на сервер. Не требует отдельного вызоват метода req.end().

server = http.createServer([requestListener]);                 // Создает сервер. Возвращает объект, который позволяет управлять данным сервером.
server.listen(port, [hostname], [backlog], [callback]);        // Начать принимать запросы по заданному port и hostname.
server.listen(path, [callback]);                               // Стартовать UNIX socket server слушая соединения по заданному пути.
server.listen(handle, [callback]);                             // Объект handle может быть или сервером или сокетом или fd.
server.close([callback]);                                      // Остановить сервер от приема новых соединений.
server.setTimeout(msecs, callback);                            // Установить значение таймаута для сокетов и излучить событие 'timeout' для объекта Server, передав socket в качестве аргумента, если случится таймаут.

server.maxHeadersCount;  // Ограничить максимальное число входящих заголовков. По умолчанию их число равно 1000. Если задать число 0, то число заголовков будет бесконечным.
server.timeout;          // Число миллисекунд неактивности до того, как сокет решит, что произошел таймаут.

server.on('request', function (request, response) { });        // Вызывается каждый раз, как только будет получен новый запрос из браузера.
server.on('connection', function (socket) { });                // Вызывается, когда будет установлено новое TCP соединение.
server.on('close', function () { });                           // Вызывается, когда сервер закрывается.
server.on('checkContinue', function (request, response) { });  // Вызывается каждый раз, когда приходит запрос с заголовком Expect: 100-continue.
server.on('connect', function (request, socket, head) { });    // Вызывается каждый раз, когда приходит запрос с типом CONNECT.
server.on('upgrade', function (request, socket, head) { });    // Вызывается каждый раз, когда клиент запрашивает апгрейд соединения.
server.on('clientError', function (exception, socket) { });    // Если клиент излучит событие  'error', то оно будет направлено сюда.

request.write(chunk, [encoding]);                              // Посылает часть данных на сервер.
request.end([data], [encoding]);                               // Завершает посылку данных на сервер.
request.abort();                                               // Обрывает запрос на сервер.
request.setTimeout(timeout, [callback]);                       // Как только сокет назначен для отправки запроса и соединен с сервером запускается функция socket.setTimeout().
request.setNoDelay([noDelay]);                                 //  Как только сокет назначен для отправки запроса и соединен с сервером запускается функция socket.setNoDelay() .
request.setSocketKeepAlive([enable], [initialDelay]);          // Как только сокет назначен для отправки запроса и соединен с сервером запускается функция socket.setKeepAlive() .

request.on('response', function(response) { });                // Вызывается как только от сервера получен ответ. Вызывается только 1 раз.
request.on('socket', function(socket) { });                    // Вызывается после того. как сокет будет присвоен для отправки запроса на сервер.
request.on('connect', function(response, socket, head) { });   // Emitted each time a server responds to a request with a CONNECT method. If this event isn't being listened for, clients receiving a CONNECT method will have their connections closed.
request.on('upgrade', function(response, socket, head) { });   // Вызывается каждый раз, когда сервер отвечает на запрос апгрейда. Если это событие не слушается, то как только клиент получит заголовок upgrade соединение будет закрыто.
request.on('continue', function() { });                        // Вызывается когда сервер посылает ответ '100 Continue', обычно по причине того, что запрос клиента содержал 'Expect: 100-continue'. Это инструкция для того, чтобы клиент послал тело запроса.

response.write(chunk, [encoding]);                             // Посылает часть данных от сервера клиенту. Если этот метод будет вызван, а метод  response.writeHead() не будет вызван, то это очистит неявные заголовки.
response.writeContinue();                                      // Послать сообщение HTTP/1.1 100 Continue в барузер, означающее, что клиент должен отправить тело запроса .
response.writeHead(statusCode, [reasonPhrase], [headers]);     // Посылает заголовок от сервера в браузер.
response.setTimeout(msecs, callback);                          // Установить значения таймаута сокета в миллисеундах.
response.setHeader(name, value);                               // Добавить заголовок в заголовки ответа сервера. Если такой заголовок уже существует, то он будет перезаписан.  Используйте массив строк, если вы хотите послать множество заголовком с одинаковым именем.
response.getHeader(name);                                      // Прочитать заголовок, который был поставлен в очередь для отправки, но еще не был отправлен в браузер. Имена заголовком чувствительны к регистру.
response.removeHeader(name);                                   // Удалиьь заголовок, который был поставлен в очередь для отправки, но еще не был отправлен в браузер.
response.addTrailers(headers);                                 // Добавить HTTP trailing headers (это такой заголовок, который отправляется в конце сообщения сервера) в ответ сервера.
response.end([data], [encoding]);                              // Этот метод сигнализирует серверу, что все заголовки и всё тело ответа сервера было отправлено в браузер. Метод response.end() обязательно должен быть вызван в конце каждого ответа сервера.

response.statusCode;                                           // Когда добавляются заголовки (без вызова метода response.writeHead()), это свойство управляет статус кодом ответа, который будет отправлен клиенту, когда заголовки будут отправлены.
response.headersSent;                                          // Булево значение (только для чтения). Равно true если заголовки к этому моменту уже отправлены в браузер, и false, если заголовки еще не были отправлены.
response.sendDate;                                             // Если задано true, то заголовок с датой будет сгенерирован автоматически и отправлен в ответе сервера, если он еще там не присутствует. По умолчанию задано true.

response.on('close', function () { });  // Вызывается, когда соединение разрывается до вызова функции response.end() или всё содержимое отправлено.
response.on('finish', function() { });  // Вызывается, когда всё содержимое отправлено из сервера в браузер.

message.httpVersion;                    // В случае запроса на сервер версия HTTP отправляется в браузер. В случае ответ ответа клиента этоHTTP версия соединения с сервером.
message.headers;                        // Объект с заголовками request/response.
message.trailers;                       // Объект с request/response trailers. Заполняется только после вызова события 'end'.
message.method;                         // Метод запроса. Строка. Только для чтения. Для примера: 'GET', 'DELETE'.
message.url;                            // URL запроса. Строка.
message.statusCode;                     // Код статуса ответа сервера. Например 404.
message.socket;                         // Объект net.Socket ассоциированный с данным соединением.

message.setTimeout(msecs, callback);    // Вызывает message.connection.setTimeout(msecs, callback).


/* *******************************************************************************************
 * URL
 * http://nodejs.org/api/url.html
 * ******************************************************************************************* */


// Этот модуль содержит функции для парсинга URL. Для их использования сделайте импорт require('url').

url.parse(urlStr, [parseQueryString], [slashesDenoteHost]);  // Преобразует URL из строки в объект.
url.format(urlObj);                                          // Преобразует объект с URL в строку.
url.resolve(from, to);                                       // Берет базовый (base) URL и href URL и соединяет их так, как если бы это сделал браузер для тэга <a href="..."></a>.


/* *******************************************************************************************
 * QUERY STRING
 * http://nodejs.org/api/querystring.html
 * ******************************************************************************************* */


// Этот модуль предоставляет функции для работы со строками с даннми браузерного запросаT. Для их использования сделайте импорт require('querystring').

querystring.stringify(obj, [sep], [eq]);         // Преобразует объект с данными в строку. Опционально можно заменить установленные по умолчанию сепаратор ('&') и символ присваивания ('=').
querystring.parse(str, [sep], [eq], [options]);  // Преобразует строку с данными в объект. Опционально можно заменить установленные по умолчанию сепаратор ('&') и символ присваивания ('=').


/* *******************************************************************************************
 * ASSERT
 * http://nodejs.org/api/assert.html
 * ******************************************************************************************* */


// Этот модуль содержит функции для написания юнит-тестов для вашей программы. Для их использования сделайте импорт require('assert').

assert.fail(actual, expected, message, operator);     // Выбрасывает исключение, которое отображает актуально и ожидаемое значения, разделенные переданным оператором
assert(value, message); и assert.ok(value, [message]);  // Проверят значение на истину. Является эквивалентом функции assert.equal(true, !!value, message);
assert.equal(actual, expected, [message]);            // Сравнивает 2 значения с помощью оператора нестрогого равенства ( == ).
assert.notEqual(actual, expected, [message]);         // Сравнивает 2 значения с помощью оператора нестрогого неравенства ( != ).
assert.deepEqual(actual, expected, [message]);        // Производит глубокую проверку равенства.
assert.notDeepEqual(actual, expected, [message]);     // Производит глубокую проверку неравенства.
assert.strictEqual(actual, expected, [message]);      // Сравнивает 2 значения с помощью оператора строгого равенства ( === ).
assert.notStrictEqual(actual, expected, [message]);   // Сравнивает 2 значения с помощью оператора строгого неравенства ( !== )
assert.throws(block, [error], [message]);             // Ожидает, что блок кода выбросит исключение error. error может быть функцией-конструктором, RegExp или функцией валидации значений.
assert.doesNotThrow(block, [message]);                // Ожидает, что блок кода не выбросит исключение error. error может быть функцией-конструктором, RegExp или функцией валидации значений.
assert.ifError(value);                                // Проверяет, что значение не равно false. Выбрасывает исключение, если оно равно true. Полезно для использования, когда первый аргумент является error в функции callbacks.


/* *******************************************************************************************
 * Операционная система
 * http://nodejs.org/api/os.html
 * ******************************************************************************************* */


// Модуль предоставляет функции для получения информации об операционной системе.
// Для их использования сделайте импорт require('os').

os.tmpdir();             // Возвращает путь до директории temp.
os.endianness();         // Возвращает порядок байт процессора. Возможные значения "BE" или "LE".
os.hostname();           // Возвращает имя компьютера.
os.type();               // Возвращает название операционной системы.
os.platform();           // Возвращает вид операционной системы.
os.arch();               // Возвращает тип архитектуры процессора.
os.release();            // Возвращает версию операционной системы.
os.uptime();             // Возвравщает время работы операционной системы в секундах.
os.loadavg();            // Возвращает массив, содержащий 1, 5, и 15 минутные значения средней нагрузки.
os.totalmem();           // Возвращает общее число байт имеющейся оперативной памяти в системе.
os.freemem();            // Возвращает число байт свободной оперативной памяти в системе.
os.cpus();               // Возвращает массив с объектами, содержащими информацию по каждому ядру или процессору, установленному в системе: модель, скорость в мегагерцах и время (объект, содержащий время потраченное ядром процессора на: user, nice, sys, idle, and irq).
os.networkInterfaces();  // Возвращает список доступных сетевых интерфейсов.
os.EOL;                  // Константа, в которой содержится маркер конца строки для данной операционной системы. Например: \r\n.


/* *******************************************************************************************
 * BUFFER
 * http://nodejs.org/api/buffer.html
 * ******************************************************************************************* */


// Buffer используется для обработки двоичных данных.
// Buffer похож на массив с числами, но он относится к сырой памяти, расположенной вне кучи V8.

Buffer.from(size);                                                  // Создает новый буфер с заданным числом октетов.
Buffer.from(array);                                                 // Создает новый буфер из массива октетов.
Buffer.from(str, [encoding]);                                       // Создает новый буфер из строки с заданной кодировкой. По умолчанию задана кодировка 'utf8'.

Buffer.isEncoding(encoding);                                        // Возвращает true, если кодировка для буфера допустима и false, если недопустима.
Buffer.isBuffer(obj);                                               // Проверяет является ли объекто буффером.
Buffer.concat(list, [totalLength]);                                 // Объединяет несколько буферов в один.
Buffer.byteLength(string, [encoding]);                              // Возвращает дину строки в байтах.

buf.write(string, [offset], [length], [encoding]);                  // Записывает строку в буфер с учетом смещения и заданной кодировки.
buf.toString([encoding], [start], [end]);                           // Преобразует буфер в строку с учетом кодировки (по умолчанию задана кодировка 'utf8') и начала (по умолчанию задано 0) и конца буфера (по умолчанию равно buffer.length).
buf.toJSON();                                                       // Преобразует буфер в формат JSON.
buf.copy(targetBuffer, [targetStart], [sourceStart], [sourceEnd]);  // Копирует значения из одного буфера в другой буфер. Исходная и целевая области буфера могут перекрываться.
buf.slice([start], [end]);                                          // Возвращает новый буфер, в который ссылается на ту же область памяти, что и старый, но со смещением offset и обрезанием от стартового start (по умолчанию равно 0) до конечного end индекса (по умолчанию равно buffer.length). Отрицательные индексы допустимы.
buf.fill(value, [offset], [end]);                                   // Заполняет этот буфер заданными значениями. Если в буфере есть значения, то они заменяются заданными.
buf[index];                                                         // Получить и установить октет буфера с данным индексом.
buf.length;                                                         // Размер буфера в байтах. The size of the buffer in bytes, Обратите внимание, что это не обязательно размер содержимого.

buffer.INSPECT_MAX_BYTES;                                           // Сколько байт максимально может быть возвращено функцией buffer.inspect(). Это значение может быть перезаписано пользователем данного модуля.

среда, 25 апреля 2018 г.

Node.js - Proxy Server

Файл index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Proxy Server</title>
</head>
<body>
    <form method="GET" action="proxy">
        <input name="proxyreq" type="text" value="http://127.0.0.2:80/" />
        <input type="submit" value="Показать" />
    </form>
</body>
</html>

Файл proxy.js (загружает также картинку favicon.png)

var http = require('http')
    , url = require('url')
    , querystring = require('querystring')
    , path = require('path')
    , fs = require('fs')
    , replaceHTML = require('./replaceHTML')
    , replaceCSS = require('./replaceCSS')
    , replaceJavaScript = require('./replaceJavaScript');

var proxyHost = '127.0.0.1'
    , proxyPort = 80;

var proxyServer = http.createServer();

proxyServer.on('request', function (proxyRequest, proxyResponse) {
    var reqUrl = url.parse(proxyRequest.url)
        , pathname = reqUrl.pathname;
    if (pathname === '/' || pathname === 'index.html') {
        fs.readFile(path.resolve(path.join(__dirname, 'index.html')), function (error, data) {
            if (error) {throw error;}
            proxyResponse.writeHead(200, 'OK', {'Content-Type': 'text/html'});
            proxyResponse.write(data);
            proxyResponse.end();
        });
    } else if (pathname === '/favicon.ico') {
        fs.readFile('./favicon.png', function (error, data) {
            if (error) {throw error;}
            response.writeHead(200, 'OK', {'Content-Type': 'image/png', 'Content-Length': Buffer.byteLength(data)});
            response.write(data);
            response.end();
        });
    } else if (pathname.indexOf('/proxyform/') === 0) {
        var proxyreq = pathname.slice('/proxyform/'.length);
        proxyreq = querystring.unescape(proxyreq);
        proxyreq = path.posix.normalize(proxyreq);
        proxyreq = proxyreq.replace('http:/', 'http://');
        var proxyUrl = url.parse(proxyreq);
        var requestOptions = {
              method: proxyRequest.method
            , protocol: proxyUrl.protocol
            , hostname: proxyUrl.hostname
            , port: proxyUrl.port
            , path: proxyUrl.pathname + (proxyRequest.method === 'GET' ? url.parse(proxyRequest.url).search : '')
            , headers: proxyRequest.headers
        };
        var requestToOutterServer = http.request(requestOptions);
        requestToOutterServer.on('response', function (outterServerResponse) {
            var outterServerResponseData = [];
            outterServerResponse.on('data', function (chunk) {outterServerResponseData.push(chunk);});
                outterServerResponse.on('end', function () {
                    if (outterServerResponse.headers['content-type'] === 'text/html') {
                        outterServerResponseData = replaceHTML(
                              outterServerResponseData.join('')
                            , 'http://' + proxyHost + ':' + proxyPort + '/proxy/?proxyreq='
                            , proxyUrl.protocol + '//' + proxyUrl.hostname + ':' + proxyUrl.port
                        );
                        outterServerResponse.headers['content-length'] = Buffer.byteLength(outterServerResponseData);
                        proxyResponse.writeHead(outterServerResponse.statusCode, outterServerResponse.statusMessage, outterServerResponse.headers);
                        proxyResponse.end(outterServerResponseData);
                    } else if (outterServerResponse.headers['content-type'] === 'text/css') {
                        outterServerResponseData = replaceCSS(
                              outterServerResponseData.join('')
                            , 'http://' + proxyHost + ':' + proxyPort + '/proxy/?proxyreq='
                            , proxyUrl.protocol + '//' + proxyUrl.hostname + ':' + proxyUrl.port
                            , path.parse(proxyUrl.pathname).dir
                        );
                        outterServerResponse.headers['content-length'] = Buffer.byteLength(outterServerResponseData);
                        proxyResponse.writeHead(outterServerResponse.statusCode, outterServerResponse.statusMessage, outterServerResponse.headers);
                        proxyResponse.end(outterServerResponseData);
                    } else if (outterServerResponse.headers['content-type'] === 'text/javascript') {
                        outterServerResponseData = replaceJavaScript(
                              outterServerResponseData.join('')
                            , 'http://' + proxyHost + ':' + proxyPort + '/proxy/?proxyreq='
                            , proxyUrl.protocol + '//' + proxyUrl.hostname + ':' + proxyUrl.port
                        );
                        outterServerResponse.headers['content-length'] = Buffer.byteLength(outterServerResponseData);
                        proxyResponse.writeHead(outterServerResponse.statusCode, outterServerResponse.statusMessage, outterServerResponse.headers);
                        proxyResponse.end(outterServerResponseData);
                    } else {
                        proxyResponse.writeHead(outterServerResponse.statusCode, outterServerResponse.statusMessage, outterServerResponse.headers);
                        outterServerResponseData.forEach(function (chunk) {
                            proxyResponse.write(chunk);
                        });
                        proxyResponse.end();
                    }
                });
        });
        requestToOutterServer.on('error', function (error) {
            console.log(requestOptions);
            /*
            console.error(error);
            proxyResponse.writeHead(500, 'Internal Server Error', {'Content-Type': 'text/html'});
            proxyResponse.write('500 Internal Server Error');
            proxyResponse.end();
            */
            throw error;
        });
        if (proxyRequest.method === 'GET') {
            requestToOutterServer.end();
        } else if (proxyRequest.method === 'POST') {
            proxyRequest.on('data', function (chunk) {requestToOutterServer.write(chunk);});
            proxyRequest.on('end', function () {requestToOutterServer.end();});
        }
    } else if (pathname.indexOf('/proxy') === 0) {
        if (reqUrl.search) {
            var searchData = reqUrl.search.slice(1);
            searchData = querystring.parse(searchData);
            var proxyreq = searchData.proxyreq;
            proxyreq = querystring.unescape(proxyreq);
            proxyreq = path.posix.normalize(proxyreq);
            proxyreq = proxyreq.replace('http:/', 'http://');
            var proxyUrl = url.parse(proxyreq);
            delete searchData.proxyreq;
            var requestOptions = {
                  method: proxyRequest.method
                , protocol: proxyUrl.protocol
                , hostname: proxyUrl.hostname
                , port: proxyUrl.port
                , path: proxyUrl.pathname + (proxyRequest.method === 'GET' ? querystring.stringify(searchData) : '')
                , headers: proxyRequest.headers
            };
            var requestToOutterServer = http.request(requestOptions);
            requestToOutterServer.on('response', function (outterServerResponse) {
                var outterServerResponseData = [];
                outterServerResponse.on('data', function (chunk) {outterServerResponseData.push(chunk);});
                outterServerResponse.on('end', function () {
                    if (outterServerResponse.headers['content-type'] === 'text/html') {
                        outterServerResponseData = replaceHTML(
                              outterServerResponseData.join('')
                            , 'http://' + proxyHost + ':' + proxyPort + '/proxy/?proxyreq='
                            , proxyUrl.protocol + '//' + proxyUrl.hostname + ':' + proxyUrl.port
                        );
                        outterServerResponse.headers['content-length'] = Buffer.byteLength(outterServerResponseData);
                        proxyResponse.writeHead(outterServerResponse.statusCode, outterServerResponse.statusMessage, outterServerResponse.headers);
                        proxyResponse.end(outterServerResponseData);
                    } else if (outterServerResponse.headers['content-type'] === 'text/css') {
                        outterServerResponseData = replaceCSS(
                              outterServerResponseData.join('')
                            , 'http://' + proxyHost + ':' + proxyPort + '/proxy/?proxyreq='
                            , proxyUrl.protocol + '//' + proxyUrl.hostname + ':' + proxyUrl.port
                            , path.parse(proxyUrl.pathname).dir
                        );
                        outterServerResponse.headers['content-length'] = Buffer.byteLength(outterServerResponseData);
                        proxyResponse.writeHead(outterServerResponse.statusCode, outterServerResponse.statusMessage, outterServerResponse.headers);
                        proxyResponse.end(outterServerResponseData);
                    } else if (outterServerResponse.headers['content-type'] === 'text/javascript') {
                        outterServerResponseData = replaceJavaScript(
                              outterServerResponseData.join('')
                            , 'http://' + proxyHost + ':' + proxyPort + '/proxy/?proxyreq='
                            , proxyUrl.protocol + '//' + proxyUrl.hostname + ':' + proxyUrl.port
                        );
                        outterServerResponse.headers['content-length'] = Buffer.byteLength(outterServerResponseData);
                        proxyResponse.writeHead(outterServerResponse.statusCode, outterServerResponse.statusMessage, outterServerResponse.headers);
                        proxyResponse.end(outterServerResponseData);
                    } else {
                        proxyResponse.writeHead(outterServerResponse.statusCode, outterServerResponse.statusMessage, outterServerResponse.headers);
                        outterServerResponseData.forEach(function (chunk) {
                            proxyResponse.write(chunk);
                        });
                        proxyResponse.end();
                    }
                });
            });
            requestToOutterServer.on('error', function (error) {
                console.log(requestOptions);
                /*
                console.error(error);
                proxyResponse.writeHead(500, 'Internal Server Error', {'Content-Type': 'text/html'});
                proxyResponse.write('500 Internal Server Error');
                proxyResponse.end();
                */
                throw error;
            });
            if (proxyRequest.method === 'GET') {
                requestToOutterServer.end();
            } else if (proxyRequest.method === 'POST') {
                proxyRequest.on('data', function (chunk) {requestToOutterServer.write(chunk);});
                proxyRequest.on('end', function () {requestToOutterServer.end();});
            }
        } else {
            proxyResponse.writeHead(200, 'OK', {'Content-Type': 'text/html'});
            proxyResponse.write('<p>Адрес не задан.</p>');
            proxyResponse.write('<a href="/">Вернуться на страницу ввода адреса.</a>');
            proxyResponse.end();
        }
    } else {
        proxyResponse.writeHead(404, 'Not Found', {'Content-Type': 'text/html'});
        proxyResponse.write('404 Not Found');
        proxyResponse.end();
    }
});

proxyServer.on('error', function (error) {throw error;});

proxyServer.listen(proxyPort, proxyHost, function () {
    console.log('Proxy server started at ' + proxyHost + ':' + proxyPort);
});

Файл replaceHTML.js

var querystring = require('querystring');

function replacePath (htmlString, regexp, proxyServerAddress, outterServerAddress) {
    return htmlString.replace(regexp, function (match, $1, $2, $3) {
        var newPath;
        if ($2.indexOf('http') === 0) {
             newPath = proxyServerAddress + querystring.escape($2);
        } else if ($2.indexOf('/') === 0) {
             newPath = proxyServerAddress + querystring.escape(outterServerAddress + $2);
        } else {
             newPath = proxyServerAddress + querystring.escape(outterServerAddress + '/' + $2);
        }
        return $1 + newPath + $3;
    });
}

function replaceHref (htmlString, proxyServerAddress, outterServerAddress) {
    return replacePath(htmlString, /(href=")([^"]+)(")/gi, proxyServerAddress, outterServerAddress)
}

/*
console.log(replaceHref([
      '<link href="style1.css" rel="stylesheet" type="text/css" />'
    , '<link href="/style2.css" rel="stylesheet" type="text/css" />'
    , '<link href="http://www.google.com/style3.css" rel="stylesheet" type="text/css" />'
].join(' | '), 'http://127.0.0.1:80/?proxyreq=', 'http://127.0.0.2:80'));
*/

function replaceSrc (htmlString, proxyServerAddress, outterServerAddress) {
    return replacePath(htmlString, /(src=")([^"]+)(")/gi, proxyServerAddress, outterServerAddress)
}

/*
console.log(replaceSrc([
      '<img src="image1.png" />'
    , '<img src="/image2.png" />'
    , '<img src="http://www.google.com/image3.png" />'
].join(' | '), 'http://127.0.0.1:80/?proxyreq=', 'http://127.0.0.2:80'));
*/

function replaceAction (htmlString, proxyServerAddress, outterServerAddress) {
    proxyServerAddress = proxyServerAddress.replace('/proxy/?proxyreq=', '/proxyform/');
    return htmlString.replace(/(action=")([^"]+)(")/gi, function (match, $1, $2, $3) {
        var newPath;
        if ($2.indexOf('http') === 0) {
             newPath = proxyServerAddress + querystring.escape($2);
        } else if ($2.indexOf('/') === 0) {
             newPath = proxyServerAddress + querystring.escape(outterServerAddress + $2);
        } else {
             newPath = proxyServerAddress + querystring.escape(outterServerAddress + '/' + $2);
        }
        return $1 + newPath + $3;
    });
    // return replacePath(htmlString, /(action=")([^"]+)(")/gi, proxyServerAddress, outterServerAddress)
}

/*
console.log(replaceAction([
      '<form action="submit" method="GET"><input name= "a" type="texy" value="1" /><input type="submit" value="Submit 1" /></form>'
    , '<form action="/submit" method="GET"><input name= "b" type="texy" value="2" /><input type="submit" value="Submit 2" /></form>'
    , '<form action="http://127.0.0.2:80/submit" method="GET"><input name= "c" type="texy" value="3" /><input type="submit" value="Submit 3" /></form>'
].join(' | '), 'http://127.0.0.1:80/?proxyreq=', 'http://127.0.0.2:80'));
*/

function replaceData (htmlString, proxyServerAddress, outterServerAddress) {
    return replacePath(htmlString, /(data=")([^"]+)(")/gi, proxyServerAddress, outterServerAddress)
}

/*
console.log(replaceData([
      '<object data="video.mp4" />'
    , '<object data="/video.mp4" />'
    , '<object data="http://www.google.com/video.mp4" />'
].join(' | '), 'http://127.0.0.1:80/?proxyreq=', 'http://127.0.0.2:80'));
*/

function replaceXMLHttpRequest (htmlString, proxyServerAddress, outterServerAddress) {
    return htmlString.replace(/<head>/gi, function () {
        return '<head>' + [
                    '<script type="text/javascript">'
                        + ';(function (open) {'
                            + 'window.XMLHttpRequest.prototype.open = function (method, url, async) {'
                                + 'var newUrl;'
                                + 'if (url.indexOf("http") === 0) {'
                                     + 'newUrl = "' + proxyServerAddress + '" + window.encodeURIComponent(url);'
                                + '} else if (url.indexOf("/") === 0) {'
                                     + 'newUrl = "' + proxyServerAddress + '" + window.encodeURIComponent("' + outterServerAddress + '" + url);'
                                + '} else {'
                                     + 'newUrl = "' + proxyServerAddress + '" + window.encodeURIComponent("' + outterServerAddress + '" + "/" + url);'
                                + '}'
                                + 'open.call(this, method, newUrl, async);'
                            + '};'
                        + '})(window.XMLHttpRequest.prototype.open);'
                    + '</script>'
                ].join('');
    });
}

/*
console.log(replaceXMLHttpRequest([
    '<!DOCTYPE html>'
    + '<html>'
    + '<head>'
    + '<link href="favicon.png" rel="icon" type="image/png" />'
    + '<link href="static/css/style1.css" rel="stylesheet" type="text/css" />'
    + '<link href="/static/css/style2.css" rel="stylesheet" type="text/css" />'
    + '<link href="http://127.0.0.2:80/static/css/style3.css" rel="stylesheet" type="text/css" />'
    + '<script src="static/js/script1.js"></script>'
    + '<script src="/static/js/script2.js"></script>'
    + '<script src="http://127.0.0.2:80/static/js/script3.js"></script>'
    + '<meta charset="utf-8" />'
    + '<title>Test page</title>'
    + '</head>'
].join('\n'), 'http://127.0.0.1:80/?proxyreq=', 'http://127.0.0.2:80'));
*/

module.exports = function replaceHTML (htmlString, proxyServerAddress, outterServerAddress) {
    htmlString = replaceHref(htmlString, proxyServerAddress, outterServerAddress);
    htmlString = replaceSrc(htmlString, proxyServerAddress, outterServerAddress);
    htmlString = replaceAction(htmlString, proxyServerAddress, outterServerAddress);
    htmlString = replaceData(htmlString, proxyServerAddress, outterServerAddress);
    htmlString = replaceXMLHttpRequest(htmlString, proxyServerAddress, outterServerAddress);
    return htmlString;
};

Файл replaceCSS.js

function replaceUrl (cssString, proxyServerAddress, outterServerAddress, rootPath) {
    return cssString.replace(/url\([^\)]+\)/gi, function (match) {
        match = match.replace(/url\(/gi, '');
        match = match.replace(/\)/gi, '');
        match = match.replace(/"/gi, '');
        match = match.replace(/'/gi, '');
        match = match.replace(/^\s+/, '');
        match = match.replace(/\s+$/, '');
        if (!(match.indexOf('/') === 0 || match.indexOf('http') === 0)) {
            match = joinPaths(rootPath, match);
        }
        var newPath;
        if (match.indexOf('http') === 0) {
            newPath = proxyServerAddress + match;
        } else if (match.indexOf('/') === 0) {
             newPath = proxyServerAddress + outterServerAddress + match;
        } else {
             newPath = proxyServerAddress + outterServerAddress + '/' + match;
        }
        return 'url("' + newPath + '")';
    });
}

function joinPaths (root, path) {
    if (path.indexOf('../') === 0) {
        if (root.indexOf('/') === root.lastIndexOf('/')) {
            if (root[root.length - 1] === '/') {root = root.slice(0, root.length - 1);}
            if (path[0] === '/') {path = path.slice(1);}
            return root + '/' + path;
        } else {
            path = path.slice(3);
            root = root.slice(0, root.lastIndexOf('/'));
            return joinPaths(root, path);
        }
    } else {
        if (root[root.length - 1] === '/') {root = root.slice(0, root.length - 1);}
        if (path[0] === '/') {path = path.slice(1);}
        return root + '/' + path;
    }
}

/*
console.log(replaceUrl([
      'body {background: url(image.png) repeat-x repeat-y;}'
    , 'div {background: url(/image.png) repeat-x repeat-y;}'
    , 'p {background: url(http://www.google.com/image.png) repeat-x repeat-y;}'

    , 'body {background: url("image.png") repeat-x repeat-y;}'
    , 'div {background: url("/image.png") repeat-x repeat-y;}'
    , 'p {background: url("http://www.google.com/image.png") repeat-x repeat-y;}'

    , '@import url(\'style2.css\');'
    , '@import url("/style2.css");'
    , '@import url("http://www.google.com/style2.css");'
].join(' | '), 'http://127.0.0.1:80/?proxyreq=', 'http://127.0.0.2:80'));
*/

module.exports = function replaceCSS (cssString, proxyServerAddress, outterServerAddress, rootPath) {
    cssString = replaceUrl(cssString, proxyServerAddress, outterServerAddress, rootPath);
    return cssString;
};

Файл replaceJavaScript.js

var querystring = require('querystring');

function replacePath (javascriptString, regexp, proxyServerAddress, outterServerAddress) {
    return javascriptString.replace(regexp, function (match, $1, $2, $3, $4) {
        var newPath;
        if ($3.indexOf('http') === 0) {
             newPath = proxyServerAddress + querystring.escape($3);
        } else if ($3.indexOf('/') === 0) {
             newPath = proxyServerAddress + querystring.escape(outterServerAddress + $3);
        } else {
             newPath = proxyServerAddress + querystring.escape(outterServerAddress + '/' + $3);
        }
        return $1 + $2 + newPath + $4;
    });
}

function replaceVarPath (javascriptString, regexp, proxyServerAddress, outterServerAddress) {
    return javascriptString.replace(regexp, function (match, $1, $2) {
        return $1 + '"' + proxyServerAddress + querystring.escape(outterServerAddress) + '/" + ' + $2;
    });
}

function replaceVarSrc (javascriptString, proxyServerAddress, outterServerAddress) {
    return replaceVarPath(javascriptString, /(\.\s*src\s*=\s*)([a-zA-Z$_]+)/gi, proxyServerAddress, outterServerAddress);
}

/*
console.log(replaceVarSrc([
      'img . src = someVar'
    , 'img.src = someVar + "/path"'
].join(' | '), 'http://127.0.0.1:80/?proxyreq=', 'http://127.0.0.2:80'));
*/

function replaceSrc (javascriptString, proxyServerAddress, outterServerAddress) {
    return replacePath(javascriptString, /(\.\s*src\s*=\s*)('|")([^'"]+)('|")/gi, proxyServerAddress, outterServerAddress);
}

/*
console.log(replaceSrc([
      'img . src = \'path\''
    , 'img.src = "/path"'
    , 'img.src="http://www.google.com/path"'
].join(' | '), 'http://127.0.0.1:80/?proxyreq=', 'http://127.0.0.2:80'));
*/

function replaceHref (javascriptString, proxyServerAddress, outterServerAddress) {
    return replacePath(javascriptString, /(\.\s*href\s*=\s*)('|")([^'"]+)('|")/gi, proxyServerAddress, outterServerAddress);
}

/*
console.log(replaceHref([
      'location . href = \'path\''
    , 'location.href = "/path"'
    , 'location.href="http://www.google.com/path"'
    , 'a . href = \'path\''
    , 'a.href = "/path"'
    , 'a.href="http://www.google.com/path"'
].join(' | '), 'http://127.0.0.1:80/?proxyreq=', 'http://127.0.0.2:80'));
*/

function replaceVarHref (javascriptString, proxyServerAddress, outterServerAddress) {
    return replaceVarPath(javascriptString, /(\.\s*href\s*=\s*)([a-zA-Z$_]+)/gi, proxyServerAddress, outterServerAddress);
}

/*
console.log(replaceVarSrc([
      'img . href = someVar'
    , 'img.href = someVar + "/path"'
].join(' | '), 'http://127.0.0.1:80/?proxyreq=', 'http://127.0.0.2:80'));
*/

module.exports = function replaceJavaScript (javascriptString, proxyServerAddress, outterServerAddress) {
    javascriptString = replaceSrc(javascriptString, proxyServerAddress, outterServerAddress);
    javascriptString = replaceVarSrc(javascriptString, proxyServerAddress, outterServerAddress);
    javascriptString = replaceHref(javascriptString, proxyServerAddress, outterServerAddress);
    javascriptString = replaceVarHref(javascriptString, proxyServerAddress, outterServerAddress);
    return javascriptString;
};